Home | History | Annotate | Download | only in skia
      1 /*
      2  * Copyright (c) 2006, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "GraphicsContext.h"
     33 
     34 #include "AffineTransform.h"
     35 #include "Color.h"
     36 #include "FloatRect.h"
     37 #include "Gradient.h"
     38 #include "GraphicsContextPlatformPrivate.h"
     39 #include "GraphicsContextPrivate.h"
     40 #include "ImageBuffer.h"
     41 #include "IntRect.h"
     42 #include "NativeImageSkia.h"
     43 #include "NotImplemented.h"
     44 #include "PlatformContextSkia.h"
     45 
     46 #include "SkBitmap.h"
     47 #include "SkBlurDrawLooper.h"
     48 #include "SkCornerPathEffect.h"
     49 #include "SkShader.h"
     50 #include "SkiaUtils.h"
     51 #include "skia/ext/platform_canvas.h"
     52 
     53 #include <math.h>
     54 #include <wtf/Assertions.h>
     55 #include <wtf/MathExtras.h>
     56 
     57 using namespace std;
     58 
     59 namespace WebCore {
     60 
     61 namespace {
     62 
     63 inline int fastMod(int value, int max)
     64 {
     65     int sign = SkExtractSign(value);
     66 
     67     value = SkApplySign(value, sign);
     68     if (value >= max)
     69         value %= max;
     70     return SkApplySign(value, sign);
     71 }
     72 
     73 inline float square(float n)
     74 {
     75     return n * n;
     76 }
     77 
     78 }  // namespace
     79 
     80 // "Seatbelt" functions ------------------------------------------------------
     81 //
     82 // These functions check certain graphics primitives for being "safe".
     83 // Skia has historically crashed when sent crazy data. These functions do
     84 // additional checking to prevent crashes.
     85 //
     86 // Ideally, all of these would be fixed in the graphics layer and we would not
     87 // have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA
     88 // flag to check the graphics layer.
     89 
     90 // Disabling these checks (20/01/2010), since we think we've fixed all the Skia
     91 // bugs.  Leaving the code in for now, so we can revert easily if necessary.
     92 // #define ENSURE_VALUE_SAFETY_FOR_SKIA
     93 
     94 static bool isCoordinateSkiaSafe(float coord)
     95 {
     96 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
     97     // First check for valid floats.
     98 #if defined(_MSC_VER)
     99     if (!_finite(coord))
    100 #else
    101     if (!finite(coord))
    102 #endif
    103         return false;
    104 
    105     // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If
    106     // the transformed point exceeds 15 bits, we just declare that it's
    107     // unreasonable to catch both of these cases.
    108     static const int maxPointMagnitude = 32767;
    109     if (coord > maxPointMagnitude || coord < -maxPointMagnitude)
    110         return false;
    111 
    112     return true;
    113 #else
    114     return true;
    115 #endif
    116 }
    117 
    118 static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt)
    119 {
    120 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
    121     // Now check for points that will overflow. We check the *transformed*
    122     // points since this is what will be rasterized.
    123     SkPoint xPt;
    124     transform.mapPoints(&xPt, &pt, 1);
    125     return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);
    126 #else
    127     return true;
    128 #endif
    129 }
    130 
    131 static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc)
    132 {
    133 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
    134     SkPoint topleft = {rc.fLeft, rc.fTop};
    135     SkPoint bottomright = {rc.fRight, rc.fBottom};
    136     return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);
    137 #else
    138     return true;
    139 #endif
    140 }
    141 
    142 bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path)
    143 {
    144 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
    145     SkPoint current_points[4];
    146     SkPath::Iter iter(path, false);
    147     for (SkPath::Verb verb = iter.next(current_points);
    148          verb != SkPath::kDone_Verb;
    149          verb = iter.next(current_points)) {
    150         switch (verb) {
    151         case SkPath::kMove_Verb:
    152             // This move will be duplicated in the next verb, so we can ignore.
    153             break;
    154         case SkPath::kLine_Verb:
    155             // iter.next returns 2 points.
    156             if (!isPointSkiaSafe(transform, current_points[0])
    157                 || !isPointSkiaSafe(transform, current_points[1]))
    158                 return false;
    159             break;
    160         case SkPath::kQuad_Verb:
    161             // iter.next returns 3 points.
    162             if (!isPointSkiaSafe(transform, current_points[0])
    163                 || !isPointSkiaSafe(transform, current_points[1])
    164                 || !isPointSkiaSafe(transform, current_points[2]))
    165                 return false;
    166             break;
    167         case SkPath::kCubic_Verb:
    168             // iter.next returns 4 points.
    169             if (!isPointSkiaSafe(transform, current_points[0])
    170                 || !isPointSkiaSafe(transform, current_points[1])
    171                 || !isPointSkiaSafe(transform, current_points[2])
    172                 || !isPointSkiaSafe(transform, current_points[3]))
    173                 return false;
    174             break;
    175         case SkPath::kClose_Verb:
    176         case SkPath::kDone_Verb:
    177         default:
    178             break;
    179         }
    180     }
    181     return true;
    182 #else
    183     return true;
    184 #endif
    185 }
    186 
    187 // Local helper functions ------------------------------------------------------
    188 
    189 void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
    190 {
    191     SkIRect ir;
    192     int rx = SkMin32(SkScalarRound(rect.width()), size.width());
    193     int ry = SkMin32(SkScalarRound(rect.height()), size.height());
    194 
    195     ir.set(-rx, -ry, rx, ry);
    196     switch (startAngle) {
    197     case 0:
    198         ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
    199         break;
    200     case 90:
    201         ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
    202         break;
    203     case 180:
    204         ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
    205         break;
    206     case 270:
    207         ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
    208         break;
    209     default:
    210         ASSERT(0);
    211     }
    212 
    213     SkRect r;
    214     r.set(ir);
    215     path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
    216 }
    217 
    218 // -----------------------------------------------------------------------------
    219 
    220 // This may be called with a NULL pointer to create a graphics context that has
    221 // no painting.
    222 GraphicsContext::GraphicsContext(PlatformGraphicsContext* gc)
    223     : m_common(createGraphicsContextPrivate())
    224     , m_data(new GraphicsContextPlatformPrivate(gc))
    225 {
    226     setPaintingDisabled(!gc || !platformContext()->canvas());
    227 }
    228 
    229 GraphicsContext::~GraphicsContext()
    230 {
    231     delete m_data;
    232     this->destroyGraphicsContextPrivate(m_common);
    233 }
    234 
    235 PlatformGraphicsContext* GraphicsContext::platformContext() const
    236 {
    237     ASSERT(!paintingDisabled());
    238     return m_data->context();
    239 }
    240 
    241 // State saving ----------------------------------------------------------------
    242 
    243 void GraphicsContext::savePlatformState()
    244 {
    245     if (paintingDisabled())
    246         return;
    247 
    248     // Save our private State.
    249     platformContext()->save();
    250 }
    251 
    252 void GraphicsContext::restorePlatformState()
    253 {
    254     if (paintingDisabled())
    255         return;
    256 
    257     // Restore our private State.
    258     platformContext()->restore();
    259 }
    260 
    261 void GraphicsContext::beginTransparencyLayer(float opacity)
    262 {
    263     if (paintingDisabled())
    264         return;
    265 
    266     // We need the "alpha" layer flag here because the base layer is opaque
    267     // (the surface of the page) but layers on top may have transparent parts.
    268     // Without explicitly setting the alpha flag, the layer will inherit the
    269     // opaque setting of the base and some things won't work properly.
    270     platformContext()->canvas()->saveLayerAlpha(
    271         0,
    272         static_cast<unsigned char>(opacity * 255),
    273         static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
    274                                          SkCanvas::kFullColorLayer_SaveFlag));
    275 }
    276 
    277 void GraphicsContext::endTransparencyLayer()
    278 {
    279     if (paintingDisabled())
    280         return;
    281     platformContext()->canvas()->restore();
    282 }
    283 
    284 // Graphics primitives ---------------------------------------------------------
    285 
    286 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
    287 {
    288     if (paintingDisabled())
    289         return;
    290 
    291     SkRect r(rect);
    292     if (!isRectSkiaSafe(getCTM(), r))
    293         return;
    294 
    295     SkPath path;
    296     path.addOval(r, SkPath::kCW_Direction);
    297     // only perform the inset if we won't invert r
    298     if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
    299         // Adding one to the thickness doesn't make the border too thick as
    300         // it's painted over afterwards. But without this adjustment the
    301         // border appears a little anemic after anti-aliasing.
    302         r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
    303         path.addOval(r, SkPath::kCCW_Direction);
    304     }
    305     platformContext()->clipPathAntiAliased(path);
    306 }
    307 
    308 void GraphicsContext::addPath(const Path& path)
    309 {
    310     if (paintingDisabled())
    311         return;
    312     platformContext()->addPath(*path.platformPath());
    313 }
    314 
    315 void GraphicsContext::beginPath()
    316 {
    317     if (paintingDisabled())
    318         return;
    319     platformContext()->beginPath();
    320 }
    321 
    322 void GraphicsContext::clearPlatformShadow()
    323 {
    324     if (paintingDisabled())
    325         return;
    326     platformContext()->setDrawLooper(0);
    327 }
    328 
    329 void GraphicsContext::clearRect(const FloatRect& rect)
    330 {
    331     if (paintingDisabled())
    332         return;
    333 
    334     SkRect r = rect;
    335     if (!isRectSkiaSafe(getCTM(), r))
    336         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    337 
    338     SkPaint paint;
    339     platformContext()->setupPaintForFilling(&paint);
    340     paint.setXfermodeMode(SkXfermode::kClear_Mode);
    341     platformContext()->canvas()->drawRect(r, paint);
    342 }
    343 
    344 void GraphicsContext::clip(const FloatRect& rect)
    345 {
    346     if (paintingDisabled())
    347         return;
    348 
    349     SkRect r(rect);
    350     if (!isRectSkiaSafe(getCTM(), r))
    351         return;
    352 
    353     platformContext()->canvas()->clipRect(r);
    354 }
    355 
    356 void GraphicsContext::clip(const Path& path)
    357 {
    358     if (paintingDisabled())
    359         return;
    360 
    361     const SkPath& p = *path.platformPath();
    362     if (!isPathSkiaSafe(getCTM(), p))
    363         return;
    364 
    365     platformContext()->clipPathAntiAliased(p);
    366 }
    367 
    368 void GraphicsContext::canvasClip(const Path& path)
    369 {
    370     if (paintingDisabled())
    371         return;
    372 
    373     const SkPath& p = *path.platformPath();
    374     if (!isPathSkiaSafe(getCTM(), p))
    375         return;
    376 
    377     platformContext()->canvas()->clipPath(p);
    378 }
    379 
    380 void GraphicsContext::clipOut(const IntRect& rect)
    381 {
    382     if (paintingDisabled())
    383         return;
    384 
    385     SkRect r(rect);
    386     if (!isRectSkiaSafe(getCTM(), r))
    387         return;
    388 
    389     platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
    390 }
    391 
    392 void GraphicsContext::clipOut(const Path& p)
    393 {
    394     if (paintingDisabled())
    395         return;
    396 
    397     const SkPath& path = *p.platformPath();
    398     if (!isPathSkiaSafe(getCTM(), path))
    399         return;
    400 
    401     platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
    402 }
    403 
    404 void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
    405 {
    406     if (paintingDisabled())
    407         return;
    408 
    409     SkRect oval(rect);
    410     if (!isRectSkiaSafe(getCTM(), oval))
    411         return;
    412 
    413     SkPath path;
    414     path.addOval(oval, SkPath::kCCW_Direction);
    415     platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
    416 }
    417 
    418 void GraphicsContext::clipPath(WindRule clipRule)
    419 {
    420     if (paintingDisabled())
    421         return;
    422 
    423     SkPath path = platformContext()->currentPathInLocalCoordinates();
    424     if (!isPathSkiaSafe(getCTM(), path))
    425         return;
    426 
    427     path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
    428     platformContext()->clipPathAntiAliased(path);
    429 }
    430 
    431 void GraphicsContext::clipToImageBuffer(const FloatRect& rect,
    432                                         const ImageBuffer* imageBuffer)
    433 {
    434     if (paintingDisabled())
    435         return;
    436 
    437 #if OS(LINUX) || OS(WINDOWS)
    438     platformContext()->beginLayerClippedToImage(rect, imageBuffer);
    439 #endif
    440 }
    441 
    442 void GraphicsContext::concatCTM(const AffineTransform& affine)
    443 {
    444     if (paintingDisabled())
    445         return;
    446     platformContext()->canvas()->concat(affine);
    447 }
    448 
    449 void GraphicsContext::drawConvexPolygon(size_t numPoints,
    450                                         const FloatPoint* points,
    451                                         bool shouldAntialias)
    452 {
    453     if (paintingDisabled())
    454         return;
    455 
    456     if (numPoints <= 1)
    457         return;
    458 
    459     SkPath path;
    460 
    461     path.incReserve(numPoints);
    462     path.moveTo(WebCoreFloatToSkScalar(points[0].x()),
    463                 WebCoreFloatToSkScalar(points[0].y()));
    464     for (size_t i = 1; i < numPoints; i++) {
    465         path.lineTo(WebCoreFloatToSkScalar(points[i].x()),
    466                     WebCoreFloatToSkScalar(points[i].y()));
    467     }
    468 
    469     if (!isPathSkiaSafe(getCTM(), path))
    470         return;
    471 
    472     SkPaint paint;
    473     platformContext()->setupPaintForFilling(&paint);
    474     platformContext()->canvas()->drawPath(path, paint);
    475 
    476     if (strokeStyle() != NoStroke) {
    477         paint.reset();
    478         platformContext()->setupPaintForStroking(&paint, 0, 0);
    479         platformContext()->canvas()->drawPath(path, paint);
    480     }
    481 }
    482 
    483 // This method is only used to draw the little circles used in lists.
    484 void GraphicsContext::drawEllipse(const IntRect& elipseRect)
    485 {
    486     if (paintingDisabled())
    487         return;
    488 
    489     SkRect rect = elipseRect;
    490     if (!isRectSkiaSafe(getCTM(), rect))
    491         return;
    492 
    493     SkPaint paint;
    494     platformContext()->setupPaintForFilling(&paint);
    495     platformContext()->canvas()->drawOval(rect, paint);
    496 
    497     if (strokeStyle() != NoStroke) {
    498         paint.reset();
    499         platformContext()->setupPaintForStroking(&paint, &rect, 0);
    500         platformContext()->canvas()->drawOval(rect, paint);
    501     }
    502 }
    503 
    504 void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
    505 {
    506     // FIXME: implement
    507 }
    508 
    509 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
    510 {
    511     if (paintingDisabled())
    512         return;
    513 
    514     unsigned rectCount = rects.size();
    515     if (!rectCount)
    516         return;
    517 
    518     SkRegion focusRingRegion;
    519     const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5);
    520     for (unsigned i = 0; i < rectCount; i++) {
    521         SkIRect r = rects[i];
    522         r.inset(-focusRingOutset, -focusRingOutset);
    523         focusRingRegion.op(r, SkRegion::kUnion_Op);
    524     }
    525 
    526     SkPath path;
    527     SkPaint paint;
    528     paint.setAntiAlias(true);
    529     paint.setStyle(SkPaint::kStroke_Style);
    530 
    531     paint.setColor(color.rgb());
    532     paint.setStrokeWidth(focusRingOutset * 2);
    533     paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
    534     focusRingRegion.getBoundaryPath(&path);
    535     platformContext()->canvas()->drawPath(path, paint);
    536 }
    537 
    538 // This is only used to draw borders.
    539 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
    540 {
    541     if (paintingDisabled())
    542         return;
    543 
    544     StrokeStyle penStyle = strokeStyle();
    545     if (penStyle == NoStroke)
    546         return;
    547 
    548     SkPaint paint;
    549     if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
    550         return;
    551 
    552     FloatPoint p1 = point1;
    553     FloatPoint p2 = point2;
    554     bool isVerticalLine = (p1.x() == p2.x());
    555     int width = roundf(strokeThickness());
    556 
    557     // We know these are vertical or horizontal lines, so the length will just
    558     // be the sum of the displacement component vectors give or take 1 -
    559     // probably worth the speed up of no square root, which also won't be exact.
    560     FloatSize disp = p2 - p1;
    561     int length = SkScalarRound(disp.width() + disp.height());
    562     platformContext()->setupPaintForStroking(&paint, 0, length);
    563 
    564     if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
    565         // Do a rect fill of our endpoints.  This ensures we always have the
    566         // appearance of being a border.  We then draw the actual dotted/dashed line.
    567 
    568         SkRect r1, r2;
    569         r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
    570         r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
    571 
    572         if (isVerticalLine) {
    573             r1.offset(-width / 2, 0);
    574             r2.offset(-width / 2, -width);
    575         } else {
    576             r1.offset(0, -width / 2);
    577             r2.offset(-width, -width / 2);
    578         }
    579         SkPaint fillPaint;
    580         fillPaint.setColor(paint.getColor());
    581         platformContext()->canvas()->drawRect(r1, fillPaint);
    582         platformContext()->canvas()->drawRect(r2, fillPaint);
    583     }
    584 
    585     adjustLineToPixelBoundaries(p1, p2, width, penStyle);
    586     SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
    587 
    588     platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
    589 }
    590 
    591 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt,
    592                                                          int width,
    593                                                          bool grammar)
    594 {
    595     if (paintingDisabled())
    596         return;
    597 
    598     // Create the pattern we'll use to draw the underline.
    599     static SkBitmap* misspellBitmap = 0;
    600     if (!misspellBitmap) {
    601         // We use a 2-pixel-high misspelling indicator because that seems to be
    602         // what WebKit is designed for, and how much room there is in a typical
    603         // page for it.
    604         const int rowPixels = 32;  // Must be multiple of 4 for pattern below.
    605         const int colPixels = 2;
    606         misspellBitmap = new SkBitmap;
    607         misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
    608                                    rowPixels, colPixels);
    609         misspellBitmap->allocPixels();
    610 
    611         misspellBitmap->eraseARGB(0, 0, 0, 0);
    612         const uint32_t lineColor = 0xFFFF0000;  // Opaque red.
    613         const uint32_t antiColor = 0x60600000;  // Semitransparent red.
    614 
    615         // Pattern:  X o   o X o   o X
    616         //             o X o   o X o
    617         uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
    618         uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
    619         for (int x = 0; x < rowPixels; x++) {
    620             switch (x % 4) {
    621             case 0:
    622                 row1[x] = lineColor;
    623                 break;
    624             case 1:
    625                 row1[x] = antiColor;
    626                 row2[x] = antiColor;
    627                 break;
    628             case 2:
    629                 row2[x] = lineColor;
    630                 break;
    631             case 3:
    632                 row1[x] = antiColor;
    633                 row2[x] = antiColor;
    634                 break;
    635             }
    636         }
    637     }
    638 
    639     // Offset it vertically by 1 so that there's some space under the text.
    640     SkScalar originX = SkIntToScalar(pt.x());
    641     SkScalar originY = SkIntToScalar(pt.y()) + 1;
    642 
    643     // Make a shader for the bitmap with an origin of the box we'll draw. This
    644     // shader is refcounted and will have an initial refcount of 1.
    645     SkShader* shader = SkShader::CreateBitmapShader(
    646         *misspellBitmap, SkShader::kRepeat_TileMode,
    647         SkShader::kRepeat_TileMode);
    648     SkMatrix matrix;
    649     matrix.reset();
    650     matrix.postTranslate(originX, originY);
    651     shader->setLocalMatrix(matrix);
    652 
    653     // Assign the shader to the paint & release our reference. The paint will
    654     // now own the shader and the shader will be destroyed when the paint goes
    655     // out of scope.
    656     SkPaint paint;
    657     paint.setShader(shader);
    658     shader->unref();
    659 
    660     SkRect rect;
    661     rect.set(originX,
    662              originY,
    663              originX + SkIntToScalar(width),
    664              originY + SkIntToScalar(misspellBitmap->height()));
    665     platformContext()->canvas()->drawRect(rect, paint);
    666 }
    667 
    668 void GraphicsContext::drawLineForText(const IntPoint& pt,
    669                                       int width,
    670                                       bool printing)
    671 {
    672     if (paintingDisabled())
    673         return;
    674 
    675     if (width <= 0)
    676         return;
    677 
    678     int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
    679     SkRect r;
    680     r.fLeft = SkIntToScalar(pt.x());
    681     r.fTop = SkIntToScalar(pt.y());
    682     r.fRight = r.fLeft + SkIntToScalar(width);
    683     r.fBottom = r.fTop + SkIntToScalar(thickness);
    684 
    685     SkPaint paint;
    686     platformContext()->setupPaintForFilling(&paint);
    687     // Text lines are drawn using the stroke color.
    688     paint.setColor(platformContext()->effectiveStrokeColor());
    689     platformContext()->canvas()->drawRect(r, paint);
    690 }
    691 
    692 // Draws a filled rectangle with a stroked border.
    693 void GraphicsContext::drawRect(const IntRect& rect)
    694 {
    695     if (paintingDisabled())
    696         return;
    697 
    698     SkRect r = rect;
    699     if (!isRectSkiaSafe(getCTM(), r)) {
    700         // See the fillRect below.
    701         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    702     }
    703 
    704     platformContext()->drawRect(r);
    705 }
    706 
    707 void GraphicsContext::fillPath()
    708 {
    709     if (paintingDisabled())
    710         return;
    711 
    712     SkPath path = platformContext()->currentPathInLocalCoordinates();
    713     if (!isPathSkiaSafe(getCTM(), path))
    714       return;
    715 
    716     const GraphicsContextState& state = m_common->state;
    717     path.setFillType(state.fillRule == RULE_EVENODD ?
    718         SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
    719 
    720     SkPaint paint;
    721     platformContext()->setupPaintForFilling(&paint);
    722 
    723     platformContext()->canvas()->drawPath(path, paint);
    724 }
    725 
    726 void GraphicsContext::fillRect(const FloatRect& rect)
    727 {
    728     if (paintingDisabled())
    729         return;
    730 
    731     SkRect r = rect;
    732     if (!isRectSkiaSafe(getCTM(), r)) {
    733         // See the other version of fillRect below.
    734         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    735     }
    736 
    737     const GraphicsContextState& state = m_common->state;
    738 
    739     SkPaint paint;
    740     platformContext()->setupPaintForFilling(&paint);
    741     platformContext()->canvas()->drawRect(r, paint);
    742 }
    743 
    744 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
    745 {
    746     if (paintingDisabled())
    747         return;
    748 
    749     SkRect r = rect;
    750     if (!isRectSkiaSafe(getCTM(), r)) {
    751         // Special case when the rectangle overflows fixed point. This is a
    752         // workaround to fix bug 1212844. When the input rectangle is very
    753         // large, it can overflow Skia's internal fixed point rect. This
    754         // should be fixable in Skia (since the output bitmap isn't that
    755         // large), but until that is fixed, we try to handle it ourselves.
    756         //
    757         // We manually clip the rectangle to the current clip rect. This
    758         // will prevent overflow. The rectangle will be transformed to the
    759         // canvas' coordinate space before it is converted to fixed point
    760         // so we are guaranteed not to overflow after doing this.
    761         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    762     }
    763 
    764     SkPaint paint;
    765     platformContext()->setupPaintCommon(&paint);
    766     paint.setColor(color.rgb());
    767     platformContext()->canvas()->drawRect(r, paint);
    768 }
    769 
    770 void GraphicsContext::fillRoundedRect(const IntRect& rect,
    771                                       const IntSize& topLeft,
    772                                       const IntSize& topRight,
    773                                       const IntSize& bottomLeft,
    774                                       const IntSize& bottomRight,
    775                                       const Color& color,
    776                                       ColorSpace colorSpace)
    777 {
    778     if (paintingDisabled())
    779         return;
    780 
    781     SkRect r = rect;
    782     if (!isRectSkiaSafe(getCTM(), r))
    783         // See fillRect().
    784         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
    785 
    786     if (topLeft.width() + topRight.width() > rect.width()
    787             || bottomLeft.width() + bottomRight.width() > rect.width()
    788             || topLeft.height() + bottomLeft.height() > rect.height()
    789             || topRight.height() + bottomRight.height() > rect.height()) {
    790         // Not all the radii fit, return a rect. This matches the behavior of
    791         // Path::createRoundedRectangle. Without this we attempt to draw a round
    792         // shadow for a square box.
    793         fillRect(rect, color, colorSpace);
    794         return;
    795     }
    796 
    797     SkPath path;
    798     addCornerArc(&path, r, topRight, 270);
    799     addCornerArc(&path, r, bottomRight, 0);
    800     addCornerArc(&path, r, bottomLeft, 90);
    801     addCornerArc(&path, r, topLeft, 180);
    802 
    803     SkPaint paint;
    804     platformContext()->setupPaintForFilling(&paint);
    805     platformContext()->canvas()->drawPath(path, paint);
    806 }
    807 
    808 AffineTransform GraphicsContext::getCTM() const
    809 {
    810     const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
    811     return AffineTransform(SkScalarToDouble(m.getScaleX()),
    812                            SkScalarToDouble(m.getSkewY()),
    813                            SkScalarToDouble(m.getSkewX()),
    814                            SkScalarToDouble(m.getScaleY()),
    815                            SkScalarToDouble(m.getTranslateX()),
    816                            SkScalarToDouble(m.getTranslateY()));
    817 }
    818 
    819 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
    820 {
    821     // This logic is copied from GraphicsContextCG, eseidel 5/05/08
    822 
    823     // It is not enough just to round to pixels in device space. The rotation
    824     // part of the affine transform matrix to device space can mess with this
    825     // conversion if we have a rotating image like the hands of the world clock
    826     // widget. We just need the scale, so we get the affine transform matrix and
    827     // extract the scale.
    828 
    829     const SkMatrix& deviceMatrix = platformContext()->canvas()->getTotalMatrix();
    830     if (deviceMatrix.isIdentity())
    831         return rect;
    832 
    833     float deviceScaleX = sqrtf(square(deviceMatrix.getScaleX())
    834         + square(deviceMatrix.getSkewY()));
    835     float deviceScaleY = sqrtf(square(deviceMatrix.getSkewX())
    836         + square(deviceMatrix.getScaleY()));
    837 
    838     FloatPoint deviceOrigin(rect.x() * deviceScaleX, rect.y() * deviceScaleY);
    839     FloatPoint deviceLowerRight((rect.x() + rect.width()) * deviceScaleX,
    840         (rect.y() + rect.height()) * deviceScaleY);
    841 
    842     deviceOrigin.setX(roundf(deviceOrigin.x()));
    843     deviceOrigin.setY(roundf(deviceOrigin.y()));
    844     deviceLowerRight.setX(roundf(deviceLowerRight.x()));
    845     deviceLowerRight.setY(roundf(deviceLowerRight.y()));
    846 
    847     // Don't let the height or width round to 0 unless either was originally 0
    848     if (deviceOrigin.y() == deviceLowerRight.y() && rect.height())
    849         deviceLowerRight.move(0, 1);
    850     if (deviceOrigin.x() == deviceLowerRight.x() && rect.width())
    851         deviceLowerRight.move(1, 0);
    852 
    853     FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX,
    854         deviceOrigin.y() / deviceScaleY);
    855     FloatPoint roundedLowerRight(deviceLowerRight.x() / deviceScaleX,
    856         deviceLowerRight.y() / deviceScaleY);
    857     return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
    858 }
    859 
    860 void GraphicsContext::scale(const FloatSize& size)
    861 {
    862     if (paintingDisabled())
    863         return;
    864     platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
    865         WebCoreFloatToSkScalar(size.height()));
    866 }
    867 
    868 void GraphicsContext::setAlpha(float alpha)
    869 {
    870     if (paintingDisabled())
    871         return;
    872     platformContext()->setAlpha(alpha);
    873 }
    874 
    875 void GraphicsContext::setCompositeOperation(CompositeOperator op)
    876 {
    877     if (paintingDisabled())
    878         return;
    879     platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
    880 }
    881 
    882 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
    883 {
    884     notImplemented();
    885 }
    886 
    887 void GraphicsContext::setLineCap(LineCap cap)
    888 {
    889     if (paintingDisabled())
    890         return;
    891     switch (cap) {
    892     case ButtCap:
    893         platformContext()->setLineCap(SkPaint::kButt_Cap);
    894         break;
    895     case RoundCap:
    896         platformContext()->setLineCap(SkPaint::kRound_Cap);
    897         break;
    898     case SquareCap:
    899         platformContext()->setLineCap(SkPaint::kSquare_Cap);
    900         break;
    901     default:
    902         ASSERT(0);
    903         break;
    904     }
    905 }
    906 
    907 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
    908 {
    909     if (paintingDisabled())
    910         return;
    911 
    912     // FIXME: This is lifted directly off SkiaSupport, lines 49-74
    913     // so it is not guaranteed to work correctly.
    914     size_t dashLength = dashes.size();
    915     if (!dashLength) {
    916         // If no dash is set, revert to solid stroke
    917         // FIXME: do we need to set NoStroke in some cases?
    918         platformContext()->setStrokeStyle(SolidStroke);
    919         platformContext()->setDashPathEffect(0);
    920         return;
    921     }
    922 
    923     size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
    924     SkScalar* intervals = new SkScalar[count];
    925 
    926     for (unsigned int i = 0; i < count; i++)
    927         intervals[i] = dashes[i % dashLength];
    928 
    929     platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
    930 
    931     delete[] intervals;
    932 }
    933 
    934 void GraphicsContext::setLineJoin(LineJoin join)
    935 {
    936     if (paintingDisabled())
    937         return;
    938     switch (join) {
    939     case MiterJoin:
    940         platformContext()->setLineJoin(SkPaint::kMiter_Join);
    941         break;
    942     case RoundJoin:
    943         platformContext()->setLineJoin(SkPaint::kRound_Join);
    944         break;
    945     case BevelJoin:
    946         platformContext()->setLineJoin(SkPaint::kBevel_Join);
    947         break;
    948     default:
    949         ASSERT(0);
    950         break;
    951     }
    952 }
    953 
    954 void GraphicsContext::setMiterLimit(float limit)
    955 {
    956     if (paintingDisabled())
    957         return;
    958     platformContext()->setMiterLimit(limit);
    959 }
    960 
    961 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
    962 {
    963     if (paintingDisabled())
    964         return;
    965     platformContext()->setFillColor(color.rgb());
    966 }
    967 
    968 void GraphicsContext::setPlatformFillGradient(Gradient* gradient)
    969 {
    970     if (paintingDisabled())
    971         return;
    972 
    973     platformContext()->setFillShader(gradient->platformGradient());
    974 }
    975 
    976 void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
    977 {
    978     if (paintingDisabled())
    979         return;
    980 
    981     platformContext()->setFillShader(pattern->platformPattern(getCTM()));
    982 }
    983 
    984 void GraphicsContext::setPlatformShadow(const IntSize& size,
    985                                         int blurInt,
    986                                         const Color& color,
    987                                         ColorSpace colorSpace)
    988 {
    989     if (paintingDisabled())
    990         return;
    991 
    992     // Detect when there's no effective shadow and clear the looper.
    993     if (!size.width() && !size.height() && !blurInt) {
    994         platformContext()->setDrawLooper(0);
    995         return;
    996     }
    997 
    998     double width = size.width();
    999     double height = size.height();
   1000     double blur = blurInt;
   1001 
   1002     // TODO(tc): This still does not address the issue that shadows
   1003     // within canvas elements should ignore transforms.
   1004     if (m_common->state.shadowsIgnoreTransforms)  {
   1005         // Currently only the GraphicsContext associated with the
   1006         // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
   1007         // Transforms. So with this flag set, we know this state is associated
   1008         // with a CanvasRenderingContext.
   1009         // CG uses natural orientation for Y axis, but the HTML5 canvas spec
   1010         // does not.
   1011         // So we now flip the height since it was flipped in
   1012         // CanvasRenderingContext in order to work with CG.
   1013         height = -height;
   1014     }
   1015 
   1016     SkColor c;
   1017     if (color.isValid())
   1018         c = color.rgb();
   1019     else
   1020         c = SkColorSetARGB(0xFF/3, 0, 0, 0);    // "std" apple shadow color.
   1021 
   1022     // TODO(tc): Should we have a max value for the blur?  CG clamps at 1000.0
   1023     // for perf reasons.
   1024     SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c);
   1025     platformContext()->setDrawLooper(dl);
   1026     dl->unref();
   1027 }
   1028 
   1029 void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
   1030 {
   1031     if (paintingDisabled())
   1032         return;
   1033 
   1034     platformContext()->setStrokeColor(strokecolor.rgb());
   1035 }
   1036 
   1037 void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& stroke)
   1038 {
   1039     if (paintingDisabled())
   1040         return;
   1041 
   1042     platformContext()->setStrokeStyle(stroke);
   1043 }
   1044 
   1045 void GraphicsContext::setPlatformStrokeThickness(float thickness)
   1046 {
   1047     if (paintingDisabled())
   1048         return;
   1049 
   1050     platformContext()->setStrokeThickness(thickness);
   1051 }
   1052 
   1053 void GraphicsContext::setPlatformStrokeGradient(Gradient* gradient)
   1054 {
   1055     if (paintingDisabled())
   1056         return;
   1057 
   1058     platformContext()->setStrokeShader(gradient->platformGradient());
   1059 }
   1060 
   1061 void GraphicsContext::setPlatformStrokePattern(Pattern* pattern)
   1062 {
   1063     if (paintingDisabled())
   1064         return;
   1065 
   1066     platformContext()->setStrokeShader(pattern->platformPattern(getCTM()));
   1067 }
   1068 
   1069 void GraphicsContext::setPlatformTextDrawingMode(int mode)
   1070 {
   1071     if (paintingDisabled())
   1072         return;
   1073 
   1074     platformContext()->setTextDrawingMode(mode);
   1075 }
   1076 
   1077 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
   1078 {
   1079 }
   1080 
   1081 void GraphicsContext::setPlatformShouldAntialias(bool enable)
   1082 {
   1083     if (paintingDisabled())
   1084         return;
   1085 
   1086     platformContext()->setUseAntialiasing(enable);
   1087 }
   1088 
   1089 void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
   1090 {
   1091     if (paintingDisabled())
   1092         return;
   1093 
   1094     SkPaint paint;
   1095     SkRect oval = r;
   1096     if (strokeStyle() == NoStroke) {
   1097         // Stroke using the fill color.
   1098         // TODO(brettw) is this really correct? It seems unreasonable.
   1099         platformContext()->setupPaintForFilling(&paint);
   1100         paint.setStyle(SkPaint::kStroke_Style);
   1101         paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
   1102     } else
   1103         platformContext()->setupPaintForStroking(&paint, 0, 0);
   1104 
   1105     // We do this before converting to scalar, so we don't overflow SkFixed.
   1106     startAngle = fastMod(startAngle, 360);
   1107     angleSpan = fastMod(angleSpan, 360);
   1108 
   1109     SkPath path;
   1110     path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
   1111     if (!isPathSkiaSafe(getCTM(), path))
   1112         return;
   1113     platformContext()->canvas()->drawPath(path, paint);
   1114 }
   1115 
   1116 void GraphicsContext::strokePath()
   1117 {
   1118     if (paintingDisabled())
   1119         return;
   1120 
   1121     SkPath path = platformContext()->currentPathInLocalCoordinates();
   1122     if (!isPathSkiaSafe(getCTM(), path))
   1123         return;
   1124 
   1125     const GraphicsContextState& state = m_common->state;
   1126 
   1127     SkPaint paint;
   1128     platformContext()->setupPaintForStroking(&paint, 0, 0);
   1129 
   1130     platformContext()->canvas()->drawPath(path, paint);
   1131 }
   1132 
   1133 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
   1134 {
   1135     if (paintingDisabled())
   1136         return;
   1137 
   1138     if (!isRectSkiaSafe(getCTM(), rect))
   1139         return;
   1140 
   1141     const GraphicsContextState& state = m_common->state;
   1142 
   1143     SkPaint paint;
   1144     platformContext()->setupPaintForStroking(&paint, 0, 0);
   1145     paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
   1146 
   1147     platformContext()->canvas()->drawRect(rect, paint);
   1148 }
   1149 
   1150 void GraphicsContext::rotate(float angleInRadians)
   1151 {
   1152     if (paintingDisabled())
   1153         return;
   1154 
   1155     platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
   1156         angleInRadians * (180.0f / 3.14159265f)));
   1157 }
   1158 
   1159 void GraphicsContext::translate(float w, float h)
   1160 {
   1161     if (paintingDisabled())
   1162         return;
   1163 
   1164     platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
   1165                                            WebCoreFloatToSkScalar(h));
   1166 }
   1167 
   1168 }  // namespace WebCore
   1169