| /* |
| * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "GraphicsContext.h" |
| |
| #include "Font.h" |
| #include "TextStyle.h" |
| |
| using namespace std; |
| |
| namespace WebCore { |
| |
| struct GraphicsContextState { |
| GraphicsContextState() |
| : strokeStyle(SolidStroke) |
| , strokeThickness(0) |
| , strokeColor(Color::black) |
| , fillColor(Color::black) |
| , textDrawingMode(cTextFill) |
| , paintingDisabled(false) |
| {} |
| |
| Font font; |
| StrokeStyle strokeStyle; |
| float strokeThickness; |
| Color strokeColor; |
| Color fillColor; |
| int textDrawingMode; |
| bool paintingDisabled; |
| }; |
| |
| class GraphicsContextPrivate { |
| public: |
| GraphicsContextPrivate(); |
| |
| GraphicsContextState state; |
| Vector<GraphicsContextState> stack; |
| Vector<IntRect> m_focusRingRects; |
| int m_focusRingWidth; |
| int m_focusRingOffset; |
| bool m_updatingControlTints; |
| }; |
| |
| GraphicsContextPrivate::GraphicsContextPrivate() |
| : m_focusRingWidth(0) |
| , m_focusRingOffset(0) |
| , m_updatingControlTints(false) |
| { |
| } |
| |
| GraphicsContextPrivate* GraphicsContext::createGraphicsContextPrivate() |
| { |
| return new GraphicsContextPrivate; |
| } |
| |
| void GraphicsContext::destroyGraphicsContextPrivate(GraphicsContextPrivate* deleteMe) |
| { |
| delete deleteMe; |
| } |
| |
| void GraphicsContext::save() |
| { |
| if (paintingDisabled()) |
| return; |
| |
| m_common->stack.append(m_common->state); |
| |
| savePlatformState(); |
| } |
| |
| void GraphicsContext::restore() |
| { |
| if (paintingDisabled()) |
| return; |
| |
| if (m_common->stack.isEmpty()) { |
| LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); |
| return; |
| } |
| m_common->state = m_common->stack.last(); |
| m_common->stack.removeLast(); |
| |
| restorePlatformState(); |
| } |
| |
| const Font& GraphicsContext::font() const |
| { |
| return m_common->state.font; |
| } |
| |
| void GraphicsContext::setFont(const Font& aFont) |
| { |
| m_common->state.font = aFont; |
| setPlatformFont(aFont); |
| } |
| |
| void GraphicsContext::setStrokeThickness(float thickness) |
| { |
| m_common->state.strokeThickness = thickness; |
| setPlatformStrokeThickness(thickness); |
| } |
| |
| void GraphicsContext::setStrokeStyle(const StrokeStyle& style) |
| { |
| m_common->state.strokeStyle = style; |
| setPlatformStrokeStyle(style); |
| } |
| |
| void GraphicsContext::setStrokeColor(const Color& color) |
| { |
| m_common->state.strokeColor = color; |
| setPlatformStrokeColor(color); |
| } |
| |
| float GraphicsContext::strokeThickness() const |
| { |
| return m_common->state.strokeThickness; |
| } |
| |
| StrokeStyle GraphicsContext::strokeStyle() const |
| { |
| return m_common->state.strokeStyle; |
| } |
| |
| Color GraphicsContext::strokeColor() const |
| { |
| return m_common->state.strokeColor; |
| } |
| |
| void GraphicsContext::setFillColor(const Color& color) |
| { |
| m_common->state.fillColor = color; |
| setPlatformFillColor(color); |
| } |
| |
| Color GraphicsContext::fillColor() const |
| { |
| return m_common->state.fillColor; |
| } |
| |
| bool GraphicsContext::updatingControlTints() const |
| { |
| return m_common->m_updatingControlTints; |
| } |
| |
| void GraphicsContext::setUpdatingControlTints(bool b) |
| { |
| setPaintingDisabled(b); |
| m_common->m_updatingControlTints = b; |
| } |
| |
| void GraphicsContext::setPaintingDisabled(bool f) |
| { |
| m_common->state.paintingDisabled = f; |
| } |
| |
| bool GraphicsContext::paintingDisabled() const |
| { |
| return m_common->state.paintingDisabled; |
| } |
| |
| void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) |
| { |
| drawImage(image, p, IntRect(0, 0, -1, -1), op); |
| } |
| |
| void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op) |
| { |
| drawImage(image, r, IntRect(0, 0, -1, -1), op); |
| } |
| |
| void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) |
| { |
| drawImage(image, IntRect(dest, srcRect.size()), srcRect, op); |
| } |
| |
| void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op) |
| { |
| drawImage(image, FloatRect(dest), srcRect, op); |
| } |
| |
| void GraphicsContext::drawText(const TextRun& run, const IntPoint& point) |
| { |
| drawText(run, point, TextStyle()); |
| } |
| |
| void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, const TextStyle& style) |
| { |
| if (paintingDisabled()) |
| return; |
| |
| font().drawText(this, run, style, point); |
| } |
| |
| void GraphicsContext::drawHighlightForText(const TextRun& run, const IntPoint& point, int h, const TextStyle& style, const Color& backgroundColor) |
| { |
| if (paintingDisabled()) |
| return; |
| |
| fillRect(font().selectionRectForText(run, style, point, h), backgroundColor); |
| } |
| |
| void GraphicsContext::initFocusRing(int width, int offset) |
| { |
| if (paintingDisabled()) |
| return; |
| clearFocusRing(); |
| |
| m_common->m_focusRingWidth = width; |
| m_common->m_focusRingOffset = offset; |
| } |
| |
| void GraphicsContext::clearFocusRing() |
| { |
| m_common->m_focusRingRects.clear(); |
| } |
| |
| IntRect GraphicsContext::focusRingBoundingRect() |
| { |
| IntRect result = IntRect(0, 0, 0, 0); |
| |
| const Vector<IntRect>& rects = focusRingRects(); |
| unsigned rectCount = rects.size(); |
| for (unsigned i = 0; i < rectCount; i++) |
| result.unite(rects[i]); |
| |
| return result; |
| } |
| |
| void GraphicsContext::addFocusRingRect(const IntRect& rect) |
| { |
| if (paintingDisabled() || rect.isEmpty()) |
| return; |
| m_common->m_focusRingRects.append(rect); |
| } |
| |
| int GraphicsContext::focusRingWidth() const |
| { |
| return m_common->m_focusRingWidth; |
| } |
| |
| int GraphicsContext::focusRingOffset() const |
| { |
| return m_common->m_focusRingOffset; |
| } |
| |
| const Vector<IntRect>& GraphicsContext::focusRingRects() const |
| { |
| return m_common->m_focusRingRects; |
| } |
| |
| void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op) |
| { |
| if (paintingDisabled()) |
| return; |
| |
| float tsw = src.width(); |
| float tsh = src.height(); |
| float tw = dest.width(); |
| float th = dest.height(); |
| |
| if (tsw == -1) |
| tsw = image->width(); |
| if (tsh == -1) |
| tsh = image->height(); |
| |
| if (tw == -1) |
| tw = image->width(); |
| if (th == -1) |
| th = image->height(); |
| |
| image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op); |
| } |
| |
| void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) |
| { |
| if (paintingDisabled()) |
| return; |
| |
| image->drawTiled(this, rect, srcPoint, tileSize, op); |
| } |
| |
| void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) |
| { |
| if (paintingDisabled()) |
| return; |
| |
| if (hRule == Image::StretchTile && vRule == Image::StretchTile) |
| // Just do a scale. |
| return drawImage(image, dest, srcRect); |
| |
| image->drawTiled(this, dest, srcRect, hRule, vRule, op); |
| } |
| |
| void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, |
| const IntSize& bottomLeft, const IntSize& bottomRight) |
| { |
| if (paintingDisabled()) |
| return; |
| |
| // Need sufficient width and height to contain these curves. Sanity check our |
| // corner radii and our width/height values to make sure the curves can all fit. |
| if (static_cast<unsigned>(rect.width()) < static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()) || |
| static_cast<unsigned>(rect.width()) < static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()) || |
| static_cast<unsigned>(rect.height()) < static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()) || |
| static_cast<unsigned>(rect.height()) < static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height())) |
| return; |
| |
| // Clip out each shape one by one. |
| clipOutEllipseInRect(IntRect(rect.x(), rect.y(), topLeft.width() * 2, topLeft.height() * 2)); |
| clipOutEllipseInRect(IntRect(rect.right() - topRight.width() * 2, rect.y(), topRight.width() * 2, topRight.height() * 2)); |
| clipOutEllipseInRect(IntRect(rect.x(), rect.bottom() - bottomLeft.height() * 2, bottomLeft.width() * 2, bottomLeft.height() * 2)); |
| clipOutEllipseInRect(IntRect(rect.right() - bottomRight.width() * 2, rect.bottom() - bottomRight.height() * 2, bottomRight.width() * 2, bottomRight.height() * 2)); |
| clipOut(IntRect(rect.x() + topLeft.width(), rect.y(), |
| rect.width() - topLeft.width() - topRight.width(), |
| max(topLeft.height(), topRight.height()))); |
| clipOut(IntRect(rect.x() + bottomLeft.width(), |
| rect.bottom() - max(bottomLeft.height(), bottomRight.height()), |
| rect.width() - bottomLeft.width() - bottomRight.width(), |
| max(bottomLeft.height(), bottomRight.height()))); |
| clipOut(IntRect(rect.x(), rect.y() + topLeft.height(), |
| max(topLeft.width(), bottomLeft.width()), rect.height() - topLeft.height() - bottomLeft.height())); |
| clipOut(IntRect(rect.right() - max(topRight.width(), bottomRight.width()), |
| rect.y() + topRight.height(), |
| max(topRight.width(), bottomRight.width()), rect.height() - topRight.height() - bottomRight.height())); |
| clipOut(IntRect(rect.x() + max(topLeft.width(), bottomLeft.width()), |
| rect.y() + max(topLeft.height(), topRight.height()), |
| rect.width() - max(topLeft.width(), bottomLeft.width()) - max(topRight.width(), bottomRight.width()), |
| rect.height() - max(topLeft.height(), topRight.height()) - max(bottomLeft.height(), bottomRight.height()))); |
| } |
| |
| int GraphicsContext::textDrawingMode() |
| { |
| return m_common->state.textDrawingMode; |
| } |
| |
| void GraphicsContext::setTextDrawingMode(int mode) |
| { |
| m_common->state.textDrawingMode = mode; |
| if (paintingDisabled()) |
| return; |
| setPlatformTextDrawingMode(mode); |
| } |
| |
| #if !PLATFORM(CG) |
| // Implement this if you want to go ahead and push the drawing mode into your native context |
| // immediately. |
| void GraphicsContext::setPlatformTextDrawingMode(int mode) |
| { |
| } |
| #endif |
| |
| #if !PLATFORM(CG) && !PLATFORM(QT) |
| void GraphicsContext::setPlatformFillColor(const Color&) |
| { |
| } |
| |
| void GraphicsContext::setPlatformStrokeColor(const Color&) |
| { |
| } |
| |
| void GraphicsContext::setPlatformStrokeThickness(float) |
| { |
| } |
| #endif |
| |
| #if !PLATFORM(QT) |
| void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) |
| { |
| } |
| |
| void GraphicsContext::setPlatformFont(const Font&) |
| { |
| } |
| #endif |
| |
| } |