diff options
author | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-12 01:50:29 +0000 |
---|---|---|
committer | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-12 01:50:29 +0000 |
commit | 4fbca13f3478efb8652b4438951de4865e53c705 (patch) | |
tree | 51bfb51593a7de74d599c5ebb5995d5cfc1de8e5 | |
parent | b18cac7c944156edce33426ea5199466936c8e51 (diff) | |
download | chromium_src-4fbca13f3478efb8652b4438951de4865e53c705.zip chromium_src-4fbca13f3478efb8652b4438951de4865e53c705.tar.gz chromium_src-4fbca13f3478efb8652b4438951de4865e53c705.tar.bz2 |
Cleanup style and alphabetize the functions in GraphicsContextSkia. It should
be much closer to WebKit style, and you can actually find the functions now.
Review URL: http://codereview.chromium.org/10407
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5249 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/port/platform/graphics/GraphicsContextSkia.cpp | 970 |
1 files changed, 497 insertions, 473 deletions
diff --git a/webkit/port/platform/graphics/GraphicsContextSkia.cpp b/webkit/port/platform/graphics/GraphicsContextSkia.cpp index 4c3f045..78ed6ce 100644 --- a/webkit/port/platform/graphics/GraphicsContextSkia.cpp +++ b/webkit/port/platform/graphics/GraphicsContextSkia.cpp @@ -1,16 +1,16 @@ /* ** Copyright 2006, Google Inc. ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -20,7 +20,6 @@ #include "GraphicsContext.h" #include "GraphicsContextPlatformPrivate.h" #include "GraphicsContextPrivate.h" -#include "wtf/MathExtras.h" #include "Assertions.h" #include "AffineTransform.h" @@ -30,11 +29,11 @@ #include "IntRect.h" #include "NativeImageSkia.h" #include "NotImplemented.h" +#include "SkBitmap.h" #include "SkBlurDrawLooper.h" #include "SkCornerPathEffect.h" #include "SkiaUtils.h" - -#include "SkBitmap.h" +#include "wtf/MathExtras.h" #include "base/gfx/platform_canvas.h" @@ -115,23 +114,23 @@ bool IsPathReasonable(const SkMatrix& transform, const SkPath& path) verb = iter.next(current_points)) { switch (verb) { case SkPath::kMove_Verb: - // This move will be duplicated in the next verb, so we can ignore it. + // This move will be duplicated in the next verb, so we can ignore. break; case SkPath::kLine_Verb: - // iter.next returns 2 points + // iter.next returns 2 points. if (!IsPointReasonable(transform, current_points[0]) || !IsPointReasonable(transform, current_points[1])) return false; break; case SkPath::kQuad_Verb: - // iter.next returns 3 points + // iter.next returns 3 points. if (!IsPointReasonable(transform, current_points[0]) || !IsPointReasonable(transform, current_points[1]) || !IsPointReasonable(transform, current_points[2])) return false; break; case SkPath::kCubic_Verb: - // iter.next returns 4 points + // iter.next returns 4 points. if (!IsPointReasonable(transform, current_points[0]) || !IsPointReasonable(transform, current_points[1]) || !IsPointReasonable(transform, current_points[2]) || @@ -152,19 +151,31 @@ bool IsPathReasonable(const SkMatrix& transform, const SkPath& path) // Local helper functions ------------------------------------------------------ -void add_corner_arc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle) +void addCornerArc(SkPath* path, + const SkRect& rect, + const IntSize& size, + int startAngle) { - SkIRect ir; - int rx = SkMin32(SkScalarRound(rect.width()), size.width()); - int ry = SkMin32(SkScalarRound(rect.height()), size.height()); - + SkIRect ir; + int rx = SkMin32(SkScalarRound(rect.width()), size.width()); + int ry = SkMin32(SkScalarRound(rect.height()), size.height()); + ir.set(-rx, -ry, rx, ry); switch (startAngle) { - case 0: ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom); break; - case 90: ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom); break; - case 180: ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop); break; - case 270: ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop); break; - default: SkASSERT(!"unexpected startAngle in add_corner_arc"); + case 0: + ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom); + break; + case 90: + ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom); + break; + case 180: + ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop); + break; + case 270: + ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop); + break; + default: + ASSERT(0); } SkRect r; @@ -172,9 +183,24 @@ void add_corner_arc(SkPath* path, const SkRect& rect, const IntSize& size, int s path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false); } +inline int fastMod(int value, int max) +{ + int sign = SkExtractSign(value); + + value = SkApplySign(value, sign); + if (value >= max) + value %= max; + return SkApplySign(value, sign); +} + +inline float square(float n) +{ + return n * n; } -//////////////////////////////////////////////////////////////////////////////////////////////// +} // namespace + +// ----------------------------------------------------------------------------- // This may be called with a NULL pointer to create a graphics context that has // no painting. @@ -191,6 +217,14 @@ GraphicsContext::~GraphicsContext() this->destroyGraphicsContextPrivate(m_common); } +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + ASSERT(!paintingDisabled()); + return m_data->context(); +} + +// State saving ---------------------------------------------------------------- + void GraphicsContext::savePlatformState() { if (paintingDisabled()) @@ -209,21 +243,257 @@ void GraphicsContext::restorePlatformState() platformContext()->restore(); } -// Draws a filled rectangle with a stroked border. -void GraphicsContext::drawRect(const IntRect& rect) +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + // We need the "alpha" layer flag here because the base layer is opaque + // (the surface of the page) but layers on top may have transparent parts. + // Without explicitly setting the alpha flag, the layer will inherit the + // opaque setting of the base and some things won't work properly. + platformContext()->canvas()->saveLayerAlpha( + 0, + static_cast<unsigned char>(opacity * 255), + static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | + SkCanvas::kFullColorLayer_SaveFlag)); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + +#if PLATFORM(WIN_OS) + platformContext()->canvas()->getTopPlatformDevice(). + fixupAlphaBeforeCompositing(); +#endif + platformContext()->canvas()->restore(); +} + +// Graphics primitives --------------------------------------------------------- + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + SkRect r(rect); + if (!IsRectReasonable(getCTM(), r)) + return; + + SkPath path; + path.addOval(r, SkPath::kCW_Direction); + // only perform the inset if we won't invert r + if (2 * thickness < rect.width() && 2 * thickness < rect.height()) { + r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness)); + path.addOval(r, SkPath::kCCW_Direction); + } + platformContext()->canvas()->clipPath(path); +} + +void GraphicsContext::addPath(const Path& path) +{ + if (paintingDisabled()) + return; + platformContext()->addPath(*path.platformPath()); +} + +void GraphicsContext::beginPath() +{ + if (paintingDisabled()) + return; + platformContext()->beginPath(); +} + +void GraphicsContext::clearPlatformShadow() +{ + if (paintingDisabled()) + return; + platformContext()->setDrawLooper(0); +} + +void GraphicsContext::clearRect(const FloatRect& rect) { if (paintingDisabled()) return; SkRect r = rect; - if (!IsRectReasonable(getCTM(), r)) { - // See the fillRect below. + if (!IsRectReasonable(getCTM(), r)) ClipRectToCanvas(*platformContext()->canvas(), r, &r); + + SkPaint paint; + platformContext()->setupPaintForFilling(&paint); + paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode); + platformContext()->canvas()->drawRect(r, paint); +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r(rect); + if (!IsRectReasonable(getCTM(), r)) + return; + + platformContext()->canvas()->clipRect(r); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + const SkPath& p = *path.platformPath(); + if (!IsPathReasonable(getCTM(), p)) + return; + + platformContext()->canvas()->clipPath(p); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r(rect); + if (!IsRectReasonable(getCTM(), r)) + return; + + platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op); +} + +void GraphicsContext::clipOut(const Path& p) +{ + if (paintingDisabled()) + return; + + const SkPath& path = *p.platformPath(); + if (!IsPathReasonable(getCTM(), path)) + return; + + platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect oval(rect); + if (!IsRectReasonable(getCTM(), oval)) + return; + + SkPath path; + path.addOval(oval, SkPath::kCCW_Direction); + platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); +} + +void GraphicsContext::clipToImageBuffer(const FloatRect& rect, + const ImageBuffer* imageBuffer) +{ + if (paintingDisabled()) + return; + + // TODO(eseidel): This is needed for image masking and complex text fills. + notImplemented(); +} + +void GraphicsContext::concatCTM(const AffineTransform& xform) +{ + if (paintingDisabled()) + return; + platformContext()->canvas()->concat(xform); +} + +void GraphicsContext::drawConvexPolygon(size_t numPoints, + const FloatPoint* points, + bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + if (numPoints <= 1) + return; + + SkPath path; + + path.incReserve(numPoints); + path.moveTo(WebCoreFloatToSkScalar(points[0].x()), + WebCoreFloatToSkScalar(points[0].y())); + for (size_t i = 1; i < numPoints; i++) { + path.lineTo(WebCoreFloatToSkScalar(points[i].x()), + WebCoreFloatToSkScalar(points[i].y())); } - platformContext()->drawRect(r); + if (!IsPathReasonable(getCTM(), path)) + return; + + SkPaint paint; + if (fillColor().rgb() & 0xFF000000) { + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawPath(path, paint); + } + + if (strokeStyle() != NoStroke) { + paint.reset(); + platformContext()->setupPaintForStroking(&paint, 0, 0); + platformContext()->canvas()->drawPath(path, paint); + } +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& elipseRect) +{ + if (paintingDisabled()) + return; + + SkRect rect = elipseRect; + if (!IsRectReasonable(getCTM(), rect)) + return; + + SkPaint paint; + if (fillColor().rgb() & 0xFF000000) { + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawOval(rect, paint); + } + if (strokeStyle() != NoStroke) { + paint.reset(); + platformContext()->setupPaintForStroking(&paint, &rect, 0); + platformContext()->canvas()->drawOval(rect, paint); + } +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + if (0 == rectCount) + return; + + SkRegion exterior_region; + const SkScalar exterior_offset = WebCoreFloatToSkScalar(0.5); + for (unsigned i = 0; i < rectCount; i++) { + SkIRect r = rects[i]; + r.inset(-exterior_offset, -exterior_offset); + exterior_region.op(r, SkRegion::kUnion_Op); + } + + SkPath path; + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + + paint.setColor(focusRingColor().rgb()); + paint.setStrokeWidth(exterior_offset * 2); + paint.setPathEffect(new SkCornerPathEffect(exterior_offset * 2))->unref(); + exterior_region.getBoundaryPath(&path); + platformContext()->canvas()->drawPath(path, paint); } - + // This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { @@ -240,57 +510,33 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) !IsPointReasonable(getCTM(), pts[1])) return; - //we know these are vertical or horizontal lines, so the length will just be the sum of the - //displacement component vectors give or take 1 - probably worth the speed up of no square - //root, which also won't be exact + // We know these are vertical or horizontal lines, so the length will just + // be the sum of the displacement component vectors give or take 1 - + // probably worth the speed up of no square root, which also won't be exact. SkPoint disp = pts[1] - pts[0]; int length = SkScalarRound(disp.fX + disp.fY); int width = roundf( platformContext()->setupPaintForStroking(&paint, 0, length)); - - // "borrowed" this comment and idea from GraphicsContextCG.cpp - // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic - // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., - // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave - // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. - + + // "Borrowed" this comment and idea from GraphicsContextCG.cpp + // For odd widths, we add in 0.5 to the appropriate x/y so that the float + // arithmetic works out. For example, with a border width of 3, KHTML will + // pass us (y1+y2)/2, e.g., (50+53)/2 = 103/2 = 51 when we want 51.5. It is + // always true that an even width gave us a perfect position, but an odd + // width gave us a position that is off by exactly 0.5. bool isVerticalLine = pts[0].fX == pts[1].fX; - - if (width & 1) //odd - { + + if (width & 1) { // Odd. if (isVerticalLine) { pts[0].fX = pts[0].fX + SK_ScalarHalf; pts[1].fX = pts[0].fX; - } else //Horizontal line - { + } else { // Horizontal line pts[0].fY = pts[0].fY + SK_ScalarHalf; pts[1].fY = pts[0].fY; } } - platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); -} - -static void setrect_for_underline(SkRect* r, GraphicsContext* context, const IntPoint& point, int width) -{ - int lineThickness = SkMax32(static_cast<int>(context->strokeThickness()), 1); - - r->fLeft = SkIntToScalar(point.x()); - r->fTop = SkIntToScalar(point.y()); - r->fRight = r->fLeft + SkIntToScalar(width); - r->fBottom = r->fTop + SkIntToScalar(lineThickness); -} - -void GraphicsContext::drawLineForText(const IntPoint& pt, int width, bool printing) -{ - if (paintingDisabled()) - return; - - SkRect r; - SkPaint paint; - - setrect_for_underline(&r, this, pt, width); - paint.setColor(this->strokeColor().rgb()); - platformContext()->canvas()->drawRect(r, paint); + platformContext()->canvas()->drawPoints( + SkCanvas::kLines_PointMode, 2, pts, paint); } void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, @@ -370,94 +616,38 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, platformContext()->canvas()->drawRect(rect, paint); } -// This method is only used to draw the little circles used in lists. -void GraphicsContext::drawEllipse(const IntRect& elipseRect) +void GraphicsContext::drawLineForText(const IntPoint& pt, + int width, + bool printing) { if (paintingDisabled()) return; - SkRect rect = elipseRect; - if (!IsRectReasonable(getCTM(), rect)) - return; - - SkPaint paint; - if (fillColor().rgb() & 0xFF000000) { - platformContext()->setupPaintForFilling(&paint); - platformContext()->canvas()->drawOval(rect, paint); - } - if (strokeStyle() != NoStroke) { - paint.reset(); - platformContext()->setupPaintForStroking(&paint, &rect, 0); - platformContext()->canvas()->drawOval(rect, paint); - } -} - -static inline int fast_mod(int value, int max) -{ - int sign = SkExtractSign(value); - - value = SkApplySign(value, sign); - if (value >= max) { - value %= max; - } - return SkApplySign(value, sign); -} - -void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan) -{ - if (paintingDisabled()) - return; + int thickness = SkMax32(static_cast<int>(strokeThickness()), 1); + SkRect r; + r.fLeft = SkIntToScalar(pt.x()); + r.fTop = SkIntToScalar(pt.y()); + r.fRight = r.fLeft + SkIntToScalar(width); + r.fBottom = r.fTop + SkIntToScalar(thickness); SkPaint paint; - SkRect oval = r; - - if (strokeStyle() == NoStroke) { - platformContext()->setupPaintForFilling(&paint); // We want the fill color. - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness())); - } else - platformContext()->setupPaintForStroking(&paint, 0, 0); - - // we do this before converting to scalar, so we don't overflow SkFixed - startAngle = fast_mod(startAngle, 360); - angleSpan = fast_mod(angleSpan, 360); - - SkPath path; - path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan)); - if (!IsPathReasonable(getCTM(), path)) - return; - platformContext()->canvas()->drawPath(path, paint); + paint.setColor(this->strokeColor().rgb()); + platformContext()->canvas()->drawRect(r, paint); } -void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias) +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) { if (paintingDisabled()) return; - if (numPoints <= 1) - return; - - SkPath path; - - path.incReserve(numPoints); - path.moveTo(WebCoreFloatToSkScalar(points[0].x()), WebCoreFloatToSkScalar(points[0].y())); - for (size_t i = 1; i < numPoints; i++) - path.lineTo(WebCoreFloatToSkScalar(points[i].x()), WebCoreFloatToSkScalar(points[i].y())); - - if (!IsPathReasonable(getCTM(), path)) - return; - - SkPaint paint; - if (fillColor().rgb() & 0xFF000000) { - platformContext()->setupPaintForFilling(&paint); - platformContext()->canvas()->drawPath(path, paint); + SkRect r = rect; + if (!IsRectReasonable(getCTM(), r)) { + // See the fillRect below. + ClipRectToCanvas(*platformContext()->canvas(), r, &r); } - if (strokeStyle() != NoStroke) { - paint.reset(); - platformContext()->setupPaintForStroking(&paint, 0, 0); - platformContext()->canvas()->drawPath(path, paint); - } + platformContext()->drawRect(r); } void GraphicsContext::fillPath() @@ -475,7 +665,7 @@ void GraphicsContext::fillPath() return; platformContext()->setFillRule(state.fillRule == RULE_EVENODD ? - SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); + SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); SkPaint paint; platformContext()->setupPaintForFilling(&paint); @@ -490,33 +680,6 @@ void GraphicsContext::fillPath() platformContext()->canvas()->drawPath(path, paint); } -void GraphicsContext::strokePath() -{ - if (paintingDisabled()) - return; - const SkPath& path = *platformContext()->currentPath(); - if (!IsPathReasonable(getCTM(), path)) - return; - - const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; - - if (colorSpace == SolidColorSpace && !strokeColor().alpha()) - return; - - SkPaint paint; - platformContext()->setupPaintForStroking(&paint, 0, 0); - - if (colorSpace == PatternColorSpace) { - SkShader* pat = state.strokePattern->createPlatformPattern(getCTM()); - paint.setShader(pat); - pat->unref(); - } else if (colorSpace == GradientColorSpace) - paint.setShader(state.strokeGradient->platformGradient()); - - platformContext()->canvas()->drawPath(path, paint); -} - void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) @@ -547,40 +710,13 @@ void GraphicsContext::fillRect(const FloatRect& rect) platformContext()->canvas()->drawRect(r, paint); } -void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) -{ - if (paintingDisabled()) - return; - if (!IsRectReasonable(getCTM(), rect)) - return; - - const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; - - if (colorSpace == SolidColorSpace && !strokeColor().alpha()) - return; - - SkPaint paint; - platformContext()->setupPaintForStroking(&paint, 0, 0); - paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); - - if (colorSpace == PatternColorSpace) { - SkShader* pat = state.strokePattern->createPlatformPattern(getCTM()); - paint.setShader(pat); - pat->unref(); - } else if (colorSpace == GradientColorSpace) - paint.setShader(state.strokeGradient->platformGradient()); - - platformContext()->canvas()->drawRect(rect, paint); -} - void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) { if (paintingDisabled()) return; if (color.rgb() & 0xFF000000) { - SkRect r = rect; + SkRect r = rect; if (!IsRectReasonable(getCTM(), r)) { // Special case when the rectangle overflows fixed point. This is a // workaround to fix bug 1212844. When the input rectangle is very @@ -602,8 +738,12 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) } } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, - const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, + const IntSize& topLeft, + const IntSize& topRight, + const IntSize& bottomLeft, + const IntSize& bottomRight, + const Color& color) { if (paintingDisabled()) return; @@ -614,11 +754,11 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef ClipRectToCanvas(*platformContext()->canvas(), r, &r); } - SkPath path; - add_corner_arc(&path, r, topRight, 270); - add_corner_arc(&path, r, bottomRight, 0); - add_corner_arc(&path, r, bottomLeft, 90); - add_corner_arc(&path, r, topLeft, 180); + SkPath path; + addCornerArc(&path, r, topRight, 270); + addCornerArc(&path, r, bottomRight, 0); + addCornerArc(&path, r, bottomLeft, 90); + addCornerArc(&path, r, topLeft, 180); SkPaint paint; platformContext()->setupPaintForFilling(&paint); @@ -626,192 +766,59 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef return fillRect(rect, color); } -void GraphicsContext::clip(const FloatRect& rect) -{ - if (paintingDisabled()) - return; - - SkRect r(rect); - if (!IsRectReasonable(getCTM(), r)) - return; - - platformContext()->canvas()->clipRect(r); -} - -void GraphicsContext::clip(const Path& path) -{ - if (paintingDisabled()) - return; - - const SkPath& p = *path.platformPath(); - if (!IsPathReasonable(getCTM(), p)) - return; - - platformContext()->canvas()->clipPath(p); -} - -void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) -{ - if (paintingDisabled()) - return; - - SkRect r(rect); - if (!IsRectReasonable(getCTM(), r)) - return; - - SkPath path; - path.addOval(r, SkPath::kCW_Direction); - // only perform the inset if we won't invert r - if (2*thickness < rect.width() && 2*thickness < rect.height()) { - r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness)); - path.addOval(r, SkPath::kCCW_Direction); - } - platformContext()->canvas()->clipPath(path); -} - - -void GraphicsContext::clipOut(const IntRect& rect) -{ - if (paintingDisabled()) - return; - - SkRect r(rect); - if (!IsRectReasonable(getCTM(), r)) - return; - - platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op); -} - -void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) -{ - if (paintingDisabled()) - return; - - SkRect oval(rect); - if (!IsRectReasonable(getCTM(), oval)) - return; - - SkPath path; - path.addOval(oval, SkPath::kCCW_Direction); - platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); -} - -void GraphicsContext::clipOut(const Path& p) -{ - if (paintingDisabled()) - return; - - const SkPath& path = *p.platformPath(); - if (!IsPathReasonable(getCTM(), path)) - return; - - platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); -} - -void GraphicsContext::beginTransparencyLayer(float opacity) -{ - if (paintingDisabled()) - return; - - // We need the "alpha" layer flag here because the base layer is opaque - // (the surface of the page) but layers on top may have transparent parts. - // Without explicitly setting the alpha flag, the layer will inherit the - // opaque setting of the base and some things won't work properly. - platformContext()->canvas()->saveLayerAlpha( - 0, - static_cast<unsigned char>(opacity * 255), - static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | - SkCanvas::kFullColorLayer_SaveFlag)); -} - -void GraphicsContext::endTransparencyLayer() -{ - if (paintingDisabled()) - return; - -#if PLATFORM(WIN_OS) - platformContext()->canvas()->getTopPlatformDevice().fixupAlphaBeforeCompositing(); -#endif - platformContext()->canvas()->restore(); -} - -void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& stroke) +AffineTransform GraphicsContext::getCTM() const { - if (paintingDisabled()) - return; - platformContext()->setStrokeStyle(stroke); + return platformContext()->canvas()->getTotalMatrix(); } -void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) { - if (paintingDisabled()) - return; + // This logic is copied from GraphicsContextCG, eseidel 5/05/08 - if (blur > 0) { - SkColor c; - - if (color.isValid()) - c = color.rgb(); - else - c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" apple shadow color - - SkDrawLooper* dl = new SkBlurDrawLooper(SkIntToScalar(blur), - SkIntToScalar(size.width()), - SkIntToScalar(size.height()), - c); - platformContext()->setDrawLooper(dl); - dl->unref(); - } else - platformContext()->setDrawLooper(0); -} + // It is not enough just to round to pixels in device space. The rotation + // part of the affine transform matrix to device space can mess with this + // conversion if we have a rotating image like the hands of the world clock + // widget. We just need the scale, so we get the affine transform matrix and + // extract the scale. -void GraphicsContext::clearPlatformShadow() -{ - if (paintingDisabled()) - return; - platformContext()->setDrawLooper(0); -} + const SkMatrix& deviceMatrix = + platformContext()->canvas()->getTotalMatrix(); + if (deviceMatrix.isIdentity()) + return rect; -void GraphicsContext::drawFocusRing(const Color& color) -{ - if (paintingDisabled()) - return; - const Vector<IntRect>& rects = focusRingRects(); - unsigned rectCount = rects.size(); - if (0 == rectCount) - return; + float deviceScaleX = sqrtf(square(deviceMatrix.getScaleX()) + + square(deviceMatrix.getSkewY())); + float deviceScaleY = sqrtf(square(deviceMatrix.getSkewX()) + + square(deviceMatrix.getScaleY())); - SkRegion exterior_region; - const SkScalar exterior_offset = WebCoreFloatToSkScalar(0.5); - for (unsigned i = 0; i < rectCount; i++) { - SkIRect r = rects[i]; - r.inset(-exterior_offset, -exterior_offset); - exterior_region.op(r, SkRegion::kUnion_Op); - } + FloatPoint deviceOrigin(rect.x() * deviceScaleX, rect.y() * deviceScaleY); + FloatPoint deviceLowerRight((rect.x() + rect.width()) * deviceScaleX, + (rect.y() + rect.height()) * deviceScaleY); - SkPath path; - SkPaint paint; - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); + deviceOrigin.setX(roundf(deviceOrigin.x())); + deviceOrigin.setY(roundf(deviceOrigin.y())); + deviceLowerRight.setX(roundf(deviceLowerRight.x())); + deviceLowerRight.setY(roundf(deviceLowerRight.y())); - paint.setColor(focusRingColor().rgb()); - paint.setStrokeWidth(exterior_offset * 2); - paint.setPathEffect(new SkCornerPathEffect(exterior_offset * 2))->unref(); - exterior_region.getBoundaryPath(&path); - platformContext()->canvas()->drawPath(path, paint); -} + // Don't let the height or width round to 0 unless either was originally 0 + if (deviceOrigin.y() == deviceLowerRight.y() && rect.height() != 0) + deviceLowerRight.move(0, 1); + if (deviceOrigin.x() == deviceLowerRight.x() && rect.width() != 0) + deviceLowerRight.move(1, 0); -PlatformGraphicsContext* GraphicsContext::platformContext() const -{ - ASSERT(!paintingDisabled()); - return m_data->context(); + FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX, + deviceOrigin.y() / deviceScaleY); + FloatPoint roundedLowerRight(deviceLowerRight.x() / deviceScaleX, + deviceLowerRight.y() / deviceScaleY); + return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); } -void GraphicsContext::setMiterLimit(float limit) +void GraphicsContext::scale(const FloatSize& size) { if (paintingDisabled()) return; - platformContext()->setMiterLimit(limit); + platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()), + WebCoreFloatToSkScalar(size.height())); } void GraphicsContext::setAlpha(float alpha) @@ -828,19 +835,9 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) platformContext()->setPorterDuffMode(WebCoreCompositeToSkiaComposite(op)); } -void GraphicsContext::clearRect(const FloatRect& rect) +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) { - if (paintingDisabled()) - return; - - SkRect r = rect; - if (!IsRectReasonable(getCTM(), r)) - ClipRectToCanvas(*platformContext()->canvas(), r, &r); - - SkPaint paint; - platformContext()->setupPaintForFilling(&paint); - paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode); - platformContext()->canvas()->drawRect(r, paint); + notImplemented(); } void GraphicsContext::setLineCap(LineCap cap) @@ -858,7 +855,7 @@ void GraphicsContext::setLineCap(LineCap cap) platformContext()->setLineCap(SkPaint::kSquare_Cap); break; default: - SkDEBUGF(("GraphicsContext::setLineCap: unknown LineCap %d\n", cap)); + ASSERT(0); break; } } @@ -877,7 +874,7 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; - for(unsigned int i = 0; i < count; i++) + for (unsigned int i = 0; i < count; i++) intervals[i] = dashes[i % dashLength]; platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, @@ -901,155 +898,182 @@ void GraphicsContext::setLineJoin(LineJoin join) platformContext()->setLineJoin(SkPaint::kBevel_Join); break; default: - SkDEBUGF(("GraphicsContext::setLineJoin: unknown LineJoin %d\n", join)); + ASSERT(0); break; } } -void GraphicsContext::scale(const FloatSize& size) +void GraphicsContext::setMiterLimit(float limit) { if (paintingDisabled()) return; - platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height())); + platformContext()->setMiterLimit(limit); } -void GraphicsContext::rotate(float angleInRadians) +void GraphicsContext::setPlatformFillColor(const Color& color) { if (paintingDisabled()) return; - platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(angleInRadians * (180.0f / 3.14159265f))); + platformContext()->setFillColor(color.rgb()); } -void GraphicsContext::translate(float w, float h) +void GraphicsContext::setPlatformShadow(const IntSize& size, + int blur, + const Color& color) { if (paintingDisabled()) return; - platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w), WebCoreFloatToSkScalar(h)); + + if (blur > 0) { + SkColor c; + if (color.isValid()) + c = color.rgb(); + else + c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" apple shadow color. + SkDrawLooper* dl = new SkBlurDrawLooper(SkIntToScalar(blur), + SkIntToScalar(size.width()), + SkIntToScalar(size.height()), + c); + platformContext()->setDrawLooper(dl); + dl->unref(); + } else + platformContext()->setDrawLooper(0); } -void GraphicsContext::concatCTM(const AffineTransform& xform) +void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor) { if (paintingDisabled()) return; - platformContext()->canvas()->concat(xform); + platformContext()->setStrokeColor(strokecolor.rgb()); } -AffineTransform GraphicsContext::getCTM() const +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& stroke) { - return platformContext()->canvas()->getTotalMatrix(); + if (paintingDisabled()) + return; + platformContext()->setStrokeStyle(stroke); } -static inline float square(float n) +void GraphicsContext::setPlatformStrokeThickness(float thickness) { - return n * n; + if (paintingDisabled()) + return; + platformContext()->setStrokeThickness(thickness); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +void GraphicsContext::setPlatformTextDrawingMode(int mode) { - // This logic is copied from GraphicsContextCG, eseidel 5/05/08 - - // It is not enough just to round to pixels in device space. The rotation - // part of the affine transform matrix to device space can mess with this - // conversion if we have a rotating image like the hands of the world clock - // widget. We just need the scale, so we get the affine transform matrix and - // extract the scale. - - const SkMatrix& deviceMatrix = platformContext()->canvas()->getTotalMatrix(); - if (deviceMatrix.isIdentity()) - return rect; - - float deviceScaleX = sqrtf(square(deviceMatrix.getScaleX()) - + square(deviceMatrix.getSkewY())); - float deviceScaleY = sqrtf(square(deviceMatrix.getSkewX()) - + square(deviceMatrix.getScaleY())); - - FloatPoint deviceOrigin(rect.x() * deviceScaleX, rect.y() * deviceScaleY); - FloatPoint deviceLowerRight((rect.x() + rect.width()) * deviceScaleX, - (rect.y() + rect.height()) * deviceScaleY); - - deviceOrigin.setX(roundf(deviceOrigin.x())); - deviceOrigin.setY(roundf(deviceOrigin.y())); - deviceLowerRight.setX(roundf(deviceLowerRight.x())); - deviceLowerRight.setY(roundf(deviceLowerRight.y())); - - // Don't let the height or width round to 0 unless either was originally 0 - if (deviceOrigin.y() == deviceLowerRight.y() && rect.height() != 0) - deviceLowerRight.move(0, 1); - if (deviceOrigin.x() == deviceLowerRight.x() && rect.width() != 0) - deviceLowerRight.move(1, 0); - - FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX, - deviceOrigin.y() / deviceScaleY); - FloatPoint roundedLowerRight(deviceLowerRight.x() / deviceScaleX, - deviceLowerRight.y() / deviceScaleY); - return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); + if (paintingDisabled()) + return; + platformContext()->setTextDrawingMode(mode); } void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) { } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setUseAntialiasing(bool enable) { if (paintingDisabled()) return; - platformContext()->setFillColor(color.rgb()); + platformContext()->setUseAntialiasing(enable); } -void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor) +void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan) { if (paintingDisabled()) return; - platformContext()->setStrokeColor(strokecolor.rgb()); -} -void GraphicsContext::setPlatformStrokeThickness(float thickness) -{ - if (paintingDisabled()) + SkPaint paint; + SkRect oval = r; + if (strokeStyle() == NoStroke) { + // Stroke using the fill color. + // TODO(brettw) is this really correct? It seems unreasonable. + platformContext()->setupPaintForFilling(&paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness())); + } else + platformContext()->setupPaintForStroking(&paint, 0, 0); + + // We do this before converting to scalar, so we don't overflow SkFixed. + startAngle = fastMod(startAngle, 360); + angleSpan = fastMod(angleSpan, 360); + + SkPath path; + path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan)); + if (!IsPathReasonable(getCTM(), path)) return; - platformContext()->setStrokeThickness(thickness); + platformContext()->canvas()->drawPath(path, paint); } -void GraphicsContext::setPlatformTextDrawingMode(int mode) +void GraphicsContext::strokePath() { if (paintingDisabled()) return; - platformContext()->setTextDrawingMode(mode); -} + const SkPath& path = *platformContext()->currentPath(); + if (!IsPathReasonable(getCTM(), path)) + return; -void GraphicsContext::addPath(const Path& path) -{ - if (paintingDisabled()) + const GraphicsContextState& state = m_common->state; + ColorSpace colorSpace = state.strokeColorSpace; + + if (colorSpace == SolidColorSpace && !strokeColor().alpha()) return; - platformContext()->addPath(*path.platformPath()); + + SkPaint paint; + platformContext()->setupPaintForStroking(&paint, 0, 0); + + if (colorSpace == PatternColorSpace) { + SkShader* pat = state.strokePattern->createPlatformPattern(getCTM()); + paint.setShader(pat); + pat->unref(); + } else if (colorSpace == GradientColorSpace) + paint.setShader(state.strokeGradient->platformGradient()); + + platformContext()->canvas()->drawPath(path, paint); } -void GraphicsContext::beginPath() +void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) { if (paintingDisabled()) return; - platformContext()->beginPath(); -} + if (!IsRectReasonable(getCTM(), rect)) + return; -void GraphicsContext::setUseAntialiasing(bool enable) -{ - if (paintingDisabled()) + const GraphicsContextState& state = m_common->state; + ColorSpace colorSpace = state.strokeColorSpace; + + if (colorSpace == SolidColorSpace && !strokeColor().alpha()) return; - platformContext()->setUseAntialiasing(enable); + + SkPaint paint; + platformContext()->setupPaintForStroking(&paint, 0, 0); + paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); + + if (colorSpace == PatternColorSpace) { + SkShader* pat = state.strokePattern->createPlatformPattern(getCTM()); + paint.setShader(pat); + pat->unref(); + } else if (colorSpace == GradientColorSpace) + paint.setShader(state.strokeGradient->platformGradient()); + + platformContext()->canvas()->drawRect(rect, paint); } -// TODO(eseidel): This is needed for image masking and complex text fills -void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer) +void GraphicsContext::rotate(float angleInRadians) { if (paintingDisabled()) return; - - notImplemented(); + platformContext()->canvas()->rotate(WebCoreFloatToSkScalar( + angleInRadians * (180.0f / 3.14159265f))); } -void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) +void GraphicsContext::translate(float w, float h) { - notImplemented(); + if (paintingDisabled()) + return; + platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w), + WebCoreFloatToSkScalar(h)); } -} +} // namespace WebCore |