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