Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
      3  * Copyright (C) 2013 Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     24  * THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/platform/graphics/GraphicsContext.h"
     29 
     30 #include "core/platform/graphics/BitmapImage.h"
     31 #include "core/platform/graphics/Gradient.h"
     32 #include "core/platform/graphics/ImageBuffer.h"
     33 #include "core/platform/graphics/IntRect.h"
     34 #include "core/platform/graphics/RoundedRect.h"
     35 #include "core/platform/graphics/TextRunIterator.h"
     36 #include "core/platform/graphics/skia/SkiaUtils.h"
     37 #include "core/platform/text/BidiResolver.h"
     38 #include "third_party/skia/include/core/SkAnnotation.h"
     39 #include "third_party/skia/include/core/SkColorFilter.h"
     40 #include "third_party/skia/include/core/SkData.h"
     41 #include "third_party/skia/include/core/SkDevice.h"
     42 #include "third_party/skia/include/core/SkRRect.h"
     43 #include "third_party/skia/include/core/SkRefCnt.h"
     44 #include "third_party/skia/include/effects/SkBlurMaskFilter.h"
     45 #include "third_party/skia/include/effects/SkCornerPathEffect.h"
     46 #include "weborigin/KURL.h"
     47 #include "wtf/Assertions.h"
     48 #include "wtf/MathExtras.h"
     49 
     50 #if OS(DARWIN)
     51 #include <ApplicationServices/ApplicationServices.h>
     52 #endif
     53 
     54 using namespace std;
     55 
     56 namespace WebCore {
     57 
     58 struct GraphicsContext::DeferredSaveState {
     59     DeferredSaveState(unsigned mask, int count) : m_flags(mask), m_restoreCount(count) { }
     60 
     61     unsigned m_flags;
     62     int m_restoreCount;
     63 };
     64 
     65 GraphicsContext::GraphicsContext(SkCanvas* canvas)
     66     : m_canvas(canvas)
     67     , m_deferredSaveFlags(0)
     68     , m_annotationMode(0)
     69 #if !ASSERT_DISABLED
     70     , m_annotationCount(0)
     71     , m_transparencyCount(0)
     72 #endif
     73     , m_trackOpaqueRegion(false)
     74     , m_trackTextRegion(false)
     75     , m_useHighResMarker(false)
     76     , m_updatingControlTints(false)
     77     , m_accelerated(false)
     78     , m_isCertainlyOpaque(true)
     79     , m_printing(false)
     80 {
     81     m_stateStack.append(adoptPtr(new GraphicsContextState()));
     82     m_state = m_stateStack.last().get();
     83 }
     84 
     85 GraphicsContext::~GraphicsContext()
     86 {
     87     ASSERT(m_stateStack.size() == 1);
     88     ASSERT(!m_annotationCount);
     89     ASSERT(!m_transparencyCount);
     90 }
     91 
     92 const SkBitmap* GraphicsContext::bitmap() const
     93 {
     94     TRACE_EVENT0("skia", "GraphicsContext::bitmap");
     95     return &m_canvas->getDevice()->accessBitmap(false);
     96 }
     97 
     98 const SkBitmap& GraphicsContext::layerBitmap(AccessMode access) const
     99 {
    100     return m_canvas->getTopDevice()->accessBitmap(access == ReadWrite);
    101 }
    102 
    103 SkDevice* GraphicsContext::createCompatibleDevice(const IntSize& size, bool hasAlpha) const
    104 {
    105     if (paintingDisabled())
    106         return 0;
    107 
    108     return m_canvas->createCompatibleDevice(SkBitmap::kARGB_8888_Config, size.width(), size.height(), !hasAlpha);
    109 }
    110 
    111 void GraphicsContext::save()
    112 {
    113     if (paintingDisabled())
    114         return;
    115 
    116     m_stateStack.append(m_state->clone());
    117     m_state = m_stateStack.last().get();
    118 
    119     m_saveStateStack.append(DeferredSaveState(m_deferredSaveFlags, m_canvas->getSaveCount()));
    120     m_deferredSaveFlags |= SkCanvas::kMatrixClip_SaveFlag;
    121 }
    122 
    123 void GraphicsContext::restore()
    124 {
    125     if (paintingDisabled())
    126         return;
    127 
    128     if (m_stateStack.size() == 1) {
    129         LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
    130         return;
    131     }
    132 
    133     if (!m_state->m_imageBufferClip.empty()) {
    134         applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
    135         m_canvas->restore();
    136     }
    137 
    138     m_stateStack.removeLast();
    139     m_state = m_stateStack.last().get();
    140 
    141     DeferredSaveState savedState = m_saveStateStack.last();
    142     m_saveStateStack.removeLast();
    143     m_deferredSaveFlags = savedState.m_flags;
    144     m_canvas->restoreToCount(savedState.m_restoreCount);
    145 }
    146 
    147 void GraphicsContext::saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags saveFlags)
    148 {
    149     if (paintingDisabled())
    150         return;
    151 
    152     realizeSave(SkCanvas::kMatrixClip_SaveFlag);
    153 
    154     m_canvas->saveLayer(bounds, paint, saveFlags);
    155     if (bounds)
    156         m_canvas->clipRect(*bounds);
    157     if (m_trackOpaqueRegion)
    158         m_opaqueRegion.pushCanvasLayer(paint);
    159 }
    160 
    161 void GraphicsContext::restoreLayer()
    162 {
    163     if (paintingDisabled())
    164         return;
    165 
    166     m_canvas->restore();
    167     if (m_trackOpaqueRegion)
    168         m_opaqueRegion.popCanvasLayer(this);
    169 }
    170 
    171 void GraphicsContext::beginAnnotation(const GraphicsContextAnnotation& annotation)
    172 {
    173     if (paintingDisabled())
    174         return;
    175 
    176     canvas()->beginCommentGroup("GraphicsContextAnnotation");
    177 
    178     AnnotationList annotations;
    179     annotation.asAnnotationList(annotations);
    180 
    181     AnnotationList::const_iterator end = annotations.end();
    182     for (AnnotationList::const_iterator it = annotations.begin(); it != end; ++it)
    183         canvas()->addComment(it->first, it->second.ascii().data());
    184 
    185 #if !ASSERT_DISABLED
    186     ++m_annotationCount;
    187 #endif
    188 }
    189 
    190 void GraphicsContext::endAnnotation()
    191 {
    192     if (paintingDisabled())
    193         return;
    194 
    195     canvas()->endCommentGroup();
    196 
    197     ASSERT(m_annotationCount > 0);
    198 #if !ASSERT_DISABLED
    199     --m_annotationCount;
    200 #endif
    201 }
    202 
    203 void GraphicsContext::setStrokeColor(const Color& color)
    204 {
    205     m_state->m_strokeData.setColor(color);
    206     m_state->m_strokeData.clearGradient();
    207     m_state->m_strokeData.clearPattern();
    208 }
    209 
    210 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
    211 {
    212     if (paintingDisabled())
    213         return;
    214 
    215     ASSERT(pattern);
    216     if (!pattern) {
    217         setStrokeColor(Color::black);
    218         return;
    219     }
    220     m_state->m_strokeData.clearGradient();
    221     m_state->m_strokeData.setPattern(pattern);
    222 }
    223 
    224 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
    225 {
    226     if (paintingDisabled())
    227         return;
    228 
    229     ASSERT(gradient);
    230     if (!gradient) {
    231         setStrokeColor(Color::black);
    232         return;
    233     }
    234     m_state->m_strokeData.setGradient(gradient);
    235     m_state->m_strokeData.clearPattern();
    236 }
    237 
    238 void GraphicsContext::setFillColor(const Color& color)
    239 {
    240     m_state->m_fillColor = color;
    241     m_state->m_fillGradient.clear();
    242     m_state->m_fillPattern.clear();
    243 }
    244 
    245 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
    246 {
    247     if (paintingDisabled())
    248         return;
    249 
    250     ASSERT(pattern);
    251     if (!pattern) {
    252         setFillColor(Color::black);
    253         return;
    254     }
    255     m_state->m_fillGradient.clear();
    256     m_state->m_fillPattern = pattern;
    257 }
    258 
    259 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
    260 {
    261     if (paintingDisabled())
    262         return;
    263 
    264     ASSERT(gradient);
    265     if (!gradient) {
    266         setFillColor(Color::black);
    267         return;
    268     }
    269     m_state->m_fillGradient = gradient;
    270     m_state->m_fillPattern.clear();
    271 }
    272 
    273 void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color,
    274     DrawLooper::ShadowTransformMode shadowTransformMode,
    275     DrawLooper::ShadowAlphaMode shadowAlphaMode)
    276 {
    277     if (paintingDisabled())
    278         return;
    279 
    280     if (!color.alpha() || (!offset.width() && !offset.height() && !blur)) {
    281         clearShadow();
    282         return;
    283     }
    284 
    285     DrawLooper drawLooper;
    286     drawLooper.addShadow(offset, blur, color, shadowTransformMode, shadowAlphaMode);
    287     drawLooper.addUnmodifiedContent();
    288     setDrawLooper(drawLooper);
    289 }
    290 
    291 void GraphicsContext::setDrawLooper(const DrawLooper& drawLooper)
    292 {
    293     if (paintingDisabled())
    294         return;
    295 
    296     m_state->m_looper = drawLooper.skDrawLooper();
    297 }
    298 
    299 void GraphicsContext::clearDrawLooper()
    300 {
    301     if (paintingDisabled())
    302         return;
    303 
    304     m_state->m_looper.clear();
    305 }
    306 
    307 bool GraphicsContext::hasShadow() const
    308 {
    309     return !!m_state->m_looper;
    310 }
    311 
    312 int GraphicsContext::getNormalizedAlpha() const
    313 {
    314     int alpha = roundf(m_state->m_alpha * 256);
    315     if (alpha > 255)
    316         alpha = 255;
    317     else if (alpha < 0)
    318         alpha = 0;
    319     return alpha;
    320 }
    321 
    322 bool GraphicsContext::getClipBounds(SkRect* bounds) const
    323 {
    324     if (paintingDisabled())
    325         return false;
    326     return m_canvas->getClipBounds(bounds);
    327 }
    328 
    329 const SkMatrix& GraphicsContext::getTotalMatrix() const
    330 {
    331     if (paintingDisabled())
    332         return SkMatrix::I();
    333     return m_canvas->getTotalMatrix();
    334 }
    335 
    336 bool GraphicsContext::isPrintingDevice() const
    337 {
    338     if (paintingDisabled())
    339         return false;
    340     return m_canvas->getTopDevice()->getDeviceCapabilities() & SkDevice::kVector_Capability;
    341 }
    342 
    343 void GraphicsContext::adjustTextRenderMode(SkPaint* paint)
    344 {
    345     if (paintingDisabled())
    346         return;
    347 
    348     if (!paint->isLCDRenderText())
    349         return;
    350 
    351     paint->setLCDRenderText(couldUseLCDRenderedText());
    352 }
    353 
    354 bool GraphicsContext::couldUseLCDRenderedText()
    355 {
    356     // Our layers only have a single alpha channel. This means that subpixel
    357     // rendered text cannot be composited correctly when the layer is
    358     // collapsed. Therefore, subpixel text is disabled when we are drawing
    359     // onto a layer.
    360     if (paintingDisabled() || isDrawingToLayer() || !isCertainlyOpaque())
    361         return false;
    362 
    363     return shouldSmoothFonts();
    364 }
    365 
    366 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation, BlendMode blendMode)
    367 {
    368     m_state->m_compositeOperator = compositeOperation;
    369     m_state->m_blendMode = blendMode;
    370     m_state->m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode);
    371 }
    372 
    373 bool GraphicsContext::readPixels(SkBitmap* bitmap, int x, int y, SkCanvas::Config8888 config8888)
    374 {
    375     if (paintingDisabled())
    376         return false;
    377 
    378     return m_canvas->readPixels(bitmap, x, y, config8888);
    379 }
    380 
    381 void GraphicsContext::setMatrix(const SkMatrix& matrix)
    382 {
    383     if (paintingDisabled())
    384         return;
    385 
    386     realizeSave(SkCanvas::kMatrix_SaveFlag);
    387 
    388     m_canvas->setMatrix(matrix);
    389 }
    390 
    391 bool GraphicsContext::concat(const SkMatrix& matrix)
    392 {
    393     if (paintingDisabled())
    394         return false;
    395 
    396     realizeSave(SkCanvas::kMatrix_SaveFlag);
    397 
    398     return m_canvas->concat(matrix);
    399 }
    400 
    401 void GraphicsContext::beginTransparencyLayer(float opacity)
    402 {
    403     if (paintingDisabled())
    404         return;
    405 
    406     // We need the "alpha" layer flag here because the base layer is opaque
    407     // (the surface of the page) but layers on top may have transparent parts.
    408     // Without explicitly setting the alpha flag, the layer will inherit the
    409     // opaque setting of the base and some things won't work properly.
    410     SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
    411 
    412     SkPaint layerPaint;
    413     layerPaint.setAlpha(static_cast<unsigned char>(opacity * 255));
    414     layerPaint.setXfermodeMode(m_state->m_xferMode);
    415 
    416     saveLayer(0, &layerPaint, saveFlags);
    417 
    418 #if !ASSERT_DISABLED
    419     ++m_transparencyCount;
    420 #endif
    421 }
    422 
    423 void GraphicsContext::endTransparencyLayer()
    424 {
    425     if (paintingDisabled())
    426         return;
    427 
    428     restoreLayer();
    429 
    430     ASSERT(m_transparencyCount > 0);
    431 #if !ASSERT_DISABLED
    432     --m_transparencyCount;
    433 #endif
    434 }
    435 
    436 void GraphicsContext::clipToImageBuffer(const ImageBuffer* imageBuffer, const FloatRect& rect)
    437 {
    438     if (paintingDisabled())
    439         return;
    440 
    441     SkRect bounds = WebCoreFloatRectToSKRect(rect);
    442 
    443     if (imageBuffer->internalSize().isEmpty()) {
    444         clipRect(bounds);
    445         return;
    446     }
    447 
    448     // Skia doesn't support clipping to an image, so we create a layer. The next
    449     // time restore is invoked the layer and |imageBuffer| are combined to
    450     // create the resulting image.
    451     m_state->m_clip = bounds;
    452 
    453     // Get the absolute coordinates of the stored clipping rectangle to make it
    454     // independent of any transform changes.
    455     getTotalMatrix().mapRect(&m_state->m_clip);
    456 
    457     SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
    458     saveLayer(&bounds, 0, saveFlags);
    459 
    460     const SkBitmap* bitmap = imageBuffer->context()->bitmap();
    461 
    462     if (m_trackOpaqueRegion) {
    463         SkRect opaqueRect = bitmap->isOpaque() ? m_state->m_clip : SkRect::MakeEmpty();
    464         m_opaqueRegion.setImageMask(opaqueRect);
    465     }
    466 
    467     // Copy off the image as |imageBuffer| may be deleted before restore is invoked.
    468     if (bitmap->isImmutable())
    469         m_state->m_imageBufferClip = *bitmap;
    470     else {
    471         // We need to make a deep-copy of the pixels themselves, so they don't
    472         // change on us between now and when we want to apply them in restore()
    473         bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
    474     }
    475 }
    476 
    477 void GraphicsContext::setupPaintForFilling(SkPaint* paint) const
    478 {
    479     if (paintingDisabled())
    480         return;
    481 
    482     setupPaintCommon(paint);
    483 
    484     setupShader(paint, m_state->m_fillGradient.get(), m_state->m_fillPattern.get(), m_state->m_fillColor.rgb());
    485 }
    486 
    487 float GraphicsContext::setupPaintForStroking(SkPaint* paint, int length) const
    488 {
    489     if (paintingDisabled())
    490         return 0.0f;
    491 
    492     setupPaintCommon(paint);
    493 
    494     setupShader(paint, m_state->m_strokeData.gradient(), m_state->m_strokeData.pattern(),
    495         m_state->m_strokeData.color().rgb());
    496 
    497     return m_state->m_strokeData.setupPaint(paint, length);
    498 }
    499 
    500 void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
    501 {
    502     if (paintingDisabled())
    503         return;
    504 
    505     if (numPoints <= 1)
    506         return;
    507 
    508     SkPath path;
    509     setPathFromConvexPoints(&path, numPoints, points);
    510 
    511     SkPaint paint;
    512     setupPaintForFilling(&paint);
    513     paint.setAntiAlias(shouldAntialias);
    514     drawPath(path, paint);
    515 
    516     if (strokeStyle() != NoStroke) {
    517         paint.reset();
    518         setupPaintForStroking(&paint);
    519         drawPath(path, paint);
    520     }
    521 }
    522 
    523 // This method is only used to draw the little circles used in lists.
    524 void GraphicsContext::drawEllipse(const IntRect& elipseRect)
    525 {
    526     if (paintingDisabled())
    527         return;
    528 
    529     SkRect rect = elipseRect;
    530     SkPaint paint;
    531     setupPaintForFilling(&paint);
    532     drawOval(rect, paint);
    533 
    534     if (strokeStyle() != NoStroke) {
    535         paint.reset();
    536         setupPaintForStroking(&paint);
    537         drawOval(rect, paint);
    538     }
    539 }
    540 
    541 void GraphicsContext::drawFocusRing(const Path& focusRingPath, int width, int offset, const Color& color)
    542 {
    543     // FIXME: Implement support for offset.
    544     UNUSED_PARAM(offset);
    545 
    546     if (paintingDisabled())
    547         return;
    548 
    549     SkPaint paint;
    550     paint.setAntiAlias(true);
    551     paint.setStyle(SkPaint::kStroke_Style);
    552     paint.setColor(color.rgb());
    553 
    554     drawOuterPath(focusRingPath.skPath(), paint, width);
    555     drawInnerPath(focusRingPath.skPath(), paint, width);
    556 }
    557 
    558 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
    559 {
    560     if (paintingDisabled())
    561         return;
    562 
    563     unsigned rectCount = rects.size();
    564     if (!rectCount)
    565         return;
    566 
    567     SkRegion focusRingRegion;
    568     const int focusRingOutset = getFocusRingOutset(offset);
    569     for (unsigned i = 0; i < rectCount; i++) {
    570         SkIRect r = rects[i];
    571         r.inset(-focusRingOutset, -focusRingOutset);
    572         focusRingRegion.op(r, SkRegion::kUnion_Op);
    573     }
    574 
    575     SkPath path;
    576     SkPaint paint;
    577     paint.setAntiAlias(true);
    578     paint.setStyle(SkPaint::kStroke_Style);
    579 
    580     paint.setColor(color.rgb());
    581     focusRingRegion.getBoundaryPath(&path);
    582     drawOuterPath(path, paint, width);
    583     drawInnerPath(path, paint, width);
    584 }
    585 
    586 static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset)
    587 {
    588     IntRect bounds(holeRect);
    589 
    590     bounds.inflate(shadowBlur);
    591 
    592     if (shadowSpread < 0)
    593         bounds.inflate(-shadowSpread);
    594 
    595     IntRect offsetBounds = bounds;
    596     offsetBounds.move(-shadowOffset);
    597     return unionRect(bounds, offsetBounds);
    598 }
    599 
    600 void GraphicsContext::drawInnerShadow(const RoundedRect& rect, const Color& shadowColor, const IntSize shadowOffset, int shadowBlur, int shadowSpread, Edges clippedEdges)
    601 {
    602     IntRect holeRect(rect.rect());
    603     holeRect.inflate(-shadowSpread);
    604 
    605     if (holeRect.isEmpty()) {
    606         if (rect.isRounded())
    607             fillRoundedRect(rect, shadowColor);
    608         else
    609             fillRect(rect.rect(), shadowColor);
    610         return;
    611     }
    612 
    613     if (clippedEdges & LeftEdge) {
    614         holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0);
    615         holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur);
    616     }
    617     if (clippedEdges & TopEdge) {
    618         holeRect.move(0, -max(shadowOffset.height(), 0) - shadowBlur);
    619         holeRect.setHeight(holeRect.height() + max(shadowOffset.height(), 0) + shadowBlur);
    620     }
    621     if (clippedEdges & RightEdge)
    622         holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur);
    623     if (clippedEdges & BottomEdge)
    624         holeRect.setHeight(holeRect.height() - min(shadowOffset.height(), 0) + shadowBlur);
    625 
    626     Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255);
    627 
    628     IntRect outerRect = areaCastingShadowInHole(rect.rect(), shadowBlur, shadowSpread, shadowOffset);
    629     RoundedRect roundedHole(holeRect, rect.radii());
    630 
    631     save();
    632     if (rect.isRounded()) {
    633         Path path;
    634         path.addRoundedRect(rect);
    635         clipPath(path);
    636         roundedHole.shrinkRadii(shadowSpread);
    637     } else {
    638         clip(rect.rect());
    639     }
    640 
    641     DrawLooper drawLooper;
    642     drawLooper.addShadow(shadowOffset, shadowBlur, shadowColor,
    643         DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha);
    644     setDrawLooper(drawLooper);
    645     fillRectWithRoundedHole(outerRect, roundedHole, fillColor);
    646     restore();
    647     clearDrawLooper();
    648 }
    649 
    650 // This is only used to draw borders.
    651 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
    652 {
    653     if (paintingDisabled())
    654         return;
    655 
    656     StrokeStyle penStyle = strokeStyle();
    657     if (penStyle == NoStroke)
    658         return;
    659 
    660     SkPaint paint;
    661     FloatPoint p1 = point1;
    662     FloatPoint p2 = point2;
    663     bool isVerticalLine = (p1.x() == p2.x());
    664     int width = roundf(strokeThickness());
    665 
    666     // We know these are vertical or horizontal lines, so the length will just
    667     // be the sum of the displacement component vectors give or take 1 -
    668     // probably worth the speed up of no square root, which also won't be exact.
    669     FloatSize disp = p2 - p1;
    670     int length = SkScalarRound(disp.width() + disp.height());
    671     setupPaintForStroking(&paint, length);
    672 
    673     if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
    674         // Do a rect fill of our endpoints.  This ensures we always have the
    675         // appearance of being a border.  We then draw the actual dotted/dashed line.
    676 
    677         SkRect r1, r2;
    678         r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
    679         r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
    680 
    681         if (isVerticalLine) {
    682             r1.offset(-width / 2, 0);
    683             r2.offset(-width / 2, -width);
    684         } else {
    685             r1.offset(0, -width / 2);
    686             r2.offset(-width, -width / 2);
    687         }
    688         SkPaint fillPaint;
    689         fillPaint.setColor(paint.getColor());
    690         drawRect(r1, fillPaint);
    691         drawRect(r2, fillPaint);
    692     }
    693 
    694     adjustLineToPixelBoundaries(p1, p2, width, penStyle);
    695     SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
    696 
    697     m_canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
    698 
    699     if (m_trackOpaqueRegion)
    700         m_opaqueRegion.didDrawPoints(this, SkCanvas::kLines_PointMode, 2, pts, paint);
    701 }
    702 
    703 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float width, DocumentMarkerLineStyle style)
    704 {
    705     if (paintingDisabled())
    706         return;
    707 
    708     int deviceScaleFactor = m_useHighResMarker ? 2 : 1;
    709 
    710     // Create the pattern we'll use to draw the underline.
    711     int index = style == DocumentMarkerGrammarLineStyle ? 1 : 0;
    712     static SkBitmap* misspellBitmap1x[2] = { 0, 0 };
    713     static SkBitmap* misspellBitmap2x[2] = { 0, 0 };
    714     SkBitmap** misspellBitmap = deviceScaleFactor == 2 ? misspellBitmap2x : misspellBitmap1x;
    715     if (!misspellBitmap[index]) {
    716 #if OS(DARWIN)
    717         // Match the artwork used by the Mac.
    718         const int rowPixels = 4 * deviceScaleFactor;
    719         const int colPixels = 3 * deviceScaleFactor;
    720         misspellBitmap[index] = new SkBitmap;
    721         misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config,
    722                                          rowPixels, colPixels);
    723         misspellBitmap[index]->allocPixels();
    724 
    725         misspellBitmap[index]->eraseARGB(0, 0, 0, 0);
    726         const uint32_t transparentColor = 0x00000000;
    727 
    728         if (deviceScaleFactor == 1) {
    729             const uint32_t colors[2][6] = {
    730                 { 0x2a2a0600, 0x57571000,  0xa8a81b00, 0xbfbf1f00,  0x70701200, 0xe0e02400 },
    731                 { 0x2a0f0f0f, 0x571e1e1e,  0xa83d3d3d, 0xbf454545,  0x70282828, 0xe0515151 }
    732             };
    733 
    734             // Pattern: a b a   a b a
    735             //          c d c   c d c
    736             //          e f e   e f e
    737             for (int x = 0; x < colPixels; ++x) {
    738                 uint32_t* row = misspellBitmap[index]->getAddr32(0, x);
    739                 row[0] = colors[index][x * 2];
    740                 row[1] = colors[index][x * 2 + 1];
    741                 row[2] = colors[index][x * 2];
    742                 row[3] = transparentColor;
    743             }
    744         } else if (deviceScaleFactor == 2) {
    745             const uint32_t colors[2][18] = {
    746                 { 0x0a090101, 0x33320806, 0x55540f0a,  0x37360906, 0x6e6c120c, 0x6e6c120c,  0x7674140d, 0x8d8b1810, 0x8d8b1810,
    747                   0x96941a11, 0xb3b01f15, 0xb3b01f15,  0x6d6b130c, 0xd9d62619, 0xd9d62619,  0x19180402, 0x7c7a150e, 0xcecb2418 },
    748                 { 0x0a020202, 0x33141414, 0x55232323,  0x37161616, 0x6e2e2e2e, 0x6e2e2e2e,  0x76313131, 0x8d3a3a3a, 0x8d3a3a3a,
    749                   0x963e3e3e, 0xb34b4b4b, 0xb34b4b4b,  0x6d2d2d2d, 0xd95b5b5b, 0xd95b5b5b,  0x19090909, 0x7c343434, 0xce575757 }
    750             };
    751 
    752             // Pattern: a b c c b a
    753             //          d e f f e d
    754             //          g h j j h g
    755             //          k l m m l k
    756             //          n o p p o n
    757             //          q r s s r q
    758             for (int x = 0; x < colPixels; ++x) {
    759                 uint32_t* row = misspellBitmap[index]->getAddr32(0, x);
    760                 row[0] = colors[index][x * 3];
    761                 row[1] = colors[index][x * 3 + 1];
    762                 row[2] = colors[index][x * 3 + 2];
    763                 row[3] = colors[index][x * 3 + 2];
    764                 row[4] = colors[index][x * 3 + 1];
    765                 row[5] = colors[index][x * 3];
    766                 row[6] = transparentColor;
    767                 row[7] = transparentColor;
    768             }
    769         } else
    770             ASSERT_NOT_REACHED();
    771 #else
    772         // We use a 2-pixel-high misspelling indicator because that seems to be
    773         // what WebKit is designed for, and how much room there is in a typical
    774         // page for it.
    775         const int rowPixels = 32 * deviceScaleFactor; // Must be multiple of 4 for pattern below.
    776         const int colPixels = 2 * deviceScaleFactor;
    777         misspellBitmap[index] = new SkBitmap;
    778         misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels);
    779         misspellBitmap[index]->allocPixels();
    780 
    781         misspellBitmap[index]->eraseARGB(0, 0, 0, 0);
    782         if (deviceScaleFactor == 1)
    783             draw1xMarker(misspellBitmap[index], index);
    784         else if (deviceScaleFactor == 2)
    785             draw2xMarker(misspellBitmap[index], index);
    786         else
    787             ASSERT_NOT_REACHED();
    788 #endif
    789     }
    790 
    791 #if OS(DARWIN)
    792     SkScalar originX = WebCoreFloatToSkScalar(pt.x()) * deviceScaleFactor;
    793     SkScalar originY = WebCoreFloatToSkScalar(pt.y()) * deviceScaleFactor;
    794 
    795     // Make sure to draw only complete dots.
    796     int rowPixels = misspellBitmap[index]->width();
    797     float widthMod = fmodf(width * deviceScaleFactor, rowPixels);
    798     if (rowPixels - widthMod > deviceScaleFactor)
    799         width -= widthMod / deviceScaleFactor;
    800 #else
    801     SkScalar originX = WebCoreFloatToSkScalar(pt.x());
    802 
    803     // Offset it vertically by 1 so that there's some space under the text.
    804     SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
    805     originX *= deviceScaleFactor;
    806     originY *= deviceScaleFactor;
    807 #endif
    808 
    809     RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader(
    810         *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
    811     SkMatrix matrix;
    812     matrix.setTranslate(originX, originY);
    813     shader->setLocalMatrix(matrix);
    814 
    815     SkPaint paint;
    816     paint.setShader(shader.get());
    817 
    818     SkRect rect;
    819     rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width) * deviceScaleFactor, originY + SkIntToScalar(misspellBitmap[index]->height()));
    820 
    821     if (deviceScaleFactor == 2) {
    822         save();
    823         scale(FloatSize(0.5, 0.5));
    824     }
    825     drawRect(rect, paint);
    826     if (deviceScaleFactor == 2)
    827         restore();
    828 }
    829 
    830 void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool printing)
    831 {
    832     if (paintingDisabled())
    833         return;
    834 
    835     if (width <= 0)
    836         return;
    837 
    838     int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
    839     SkRect r;
    840     r.fLeft = WebCoreFloatToSkScalar(pt.x());
    841     // Avoid anti-aliasing lines. Currently, these are always horizontal.
    842     // Round to nearest pixel to match text and other content.
    843     r.fTop = WebCoreFloatToSkScalar(floorf(pt.y() + 0.5f));
    844     r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
    845     r.fBottom = r.fTop + SkIntToScalar(thickness);
    846 
    847     SkPaint paint;
    848     switch (strokeStyle()) {
    849     case NoStroke:
    850     case SolidStroke:
    851     case DoubleStroke:
    852     case WavyStroke:
    853         setupPaintForFilling(&paint);
    854         break;
    855     case DottedStroke:
    856     case DashedStroke:
    857         setupPaintForStroking(&paint);
    858         break;
    859     }
    860 
    861     // Text lines are drawn using the stroke color.
    862     paint.setColor(effectiveStrokeColor());
    863     drawRect(r, paint);
    864 }
    865 
    866 // Draws a filled rectangle with a stroked border.
    867 void GraphicsContext::drawRect(const IntRect& rect)
    868 {
    869     if (paintingDisabled())
    870         return;
    871 
    872     ASSERT(!rect.isEmpty());
    873     if (rect.isEmpty())
    874         return;
    875 
    876     SkRect skRect = rect;
    877     SkPaint paint;
    878     int fillcolorNotTransparent = m_state->m_fillColor.rgb() & 0xFF000000;
    879     if (fillcolorNotTransparent) {
    880         setupPaintForFilling(&paint);
    881         drawRect(skRect, paint);
    882     }
    883 
    884     if (m_state->m_strokeData.style() != NoStroke && (m_state->m_strokeData.color().rgb() & 0xFF000000)) {
    885         // We do a fill of four rects to simulate the stroke of a border.
    886         paint.reset();
    887         setupPaintForFilling(&paint);
    888         // need to jam in the strokeColor
    889         paint.setColor(this->effectiveStrokeColor());
    890 
    891         SkRect topBorder = { skRect.fLeft, skRect.fTop, skRect.fRight, skRect.fTop + 1 };
    892         drawRect(topBorder, paint);
    893         SkRect bottomBorder = { skRect.fLeft, skRect.fBottom - 1, skRect.fRight, skRect.fBottom };
    894         drawRect(bottomBorder, paint);
    895         SkRect leftBorder = { skRect.fLeft, skRect.fTop + 1, skRect.fLeft + 1, skRect.fBottom - 1 };
    896         drawRect(leftBorder, paint);
    897         SkRect rightBorder = { skRect.fRight - 1, skRect.fTop + 1, skRect.fRight, skRect.fBottom - 1 };
    898         drawRect(rightBorder, paint);
    899     }
    900 }
    901 
    902 void GraphicsContext::drawText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point)
    903 {
    904     if (paintingDisabled())
    905         return;
    906 
    907     font.drawText(this, runInfo, point);
    908 }
    909 
    910 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point)
    911 {
    912     if (paintingDisabled())
    913         return;
    914 
    915     font.drawEmphasisMarks(this, runInfo, mark, point);
    916 }
    917 
    918 void GraphicsContext::drawBidiText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction)
    919 {
    920     if (paintingDisabled())
    921         return;
    922 
    923     // sub-run painting is not supported for Bidi text.
    924     const TextRun& run = runInfo.run;
    925     ASSERT((runInfo.from == 0) && (runInfo.to == run.length()));
    926     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    927     bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
    928     bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
    929 
    930     // FIXME: This ownership should be reversed. We should pass BidiRunList
    931     // to BidiResolver in createBidiRunsForLine.
    932     BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    933     bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
    934     if (!bidiRuns.runCount())
    935         return;
    936 
    937     FloatPoint currPoint = point;
    938     BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    939     while (bidiRun) {
    940         TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
    941         bool isRTL = bidiRun->level() % 2;
    942         subrun.setDirection(isRTL ? RTL : LTR);
    943         subrun.setDirectionalOverride(bidiRun->dirOverride(false));
    944 
    945         TextRunPaintInfo subrunInfo(subrun);
    946         subrunInfo.bounds = runInfo.bounds;
    947         font.drawText(this, subrunInfo, currPoint, customFontNotReadyAction);
    948 
    949         bidiRun = bidiRun->next();
    950         // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
    951         if (bidiRun)
    952             currPoint.move(font.width(subrun), 0);
    953     }
    954 
    955     bidiRuns.deleteRuns();
    956 }
    957 
    958 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, int from, int to)
    959 {
    960     if (paintingDisabled())
    961         return;
    962 
    963     fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor);
    964 }
    965 
    966 void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
    967 {
    968     if (!image)
    969         return;
    970     drawImage(image, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation);
    971 }
    972 
    973 void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
    974 {
    975     if (!image)
    976         return;
    977     drawImage(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation, useLowQualityScale);
    978 }
    979 
    980 void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
    981 {
    982     drawImage(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, shouldRespectImageOrientation);
    983 }
    984 
    985 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
    986 {
    987     drawImage(image, dest, src, op, BlendModeNormal, shouldRespectImageOrientation, useLowQualityScale);
    988 }
    989 
    990 void GraphicsContext::drawImage(Image* image, const FloatRect& dest)
    991 {
    992     if (!image)
    993         return;
    994     drawImage(image, dest, FloatRect(IntRect(IntPoint(), image->size())));
    995 }
    996 
    997 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
    998 {    if (paintingDisabled() || !image)
    999         return;
   1000 
   1001     InterpolationQuality previousInterpolationQuality = InterpolationDefault;
   1002 
   1003     if (useLowQualityScale) {
   1004         previousInterpolationQuality = imageInterpolationQuality();
   1005         setImageInterpolationQuality(InterpolationLow);
   1006     }
   1007 
   1008     image->draw(this, dest, src, op, blendMode, shouldRespectImageOrientation);
   1009 
   1010     if (useLowQualityScale)
   1011         setImageInterpolationQuality(previousInterpolationQuality);
   1012 }
   1013 
   1014 void GraphicsContext::drawTiledImage(Image* image, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale, BlendMode blendMode)
   1015 {
   1016     if (paintingDisabled() || !image)
   1017         return;
   1018 
   1019     if (useLowQualityScale) {
   1020         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
   1021         setImageInterpolationQuality(InterpolationLow);
   1022         image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode);
   1023         setImageInterpolationQuality(previousInterpolationQuality);
   1024     } else {
   1025         image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode);
   1026     }
   1027 }
   1028 
   1029 void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect,
   1030     const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
   1031 {
   1032     if (paintingDisabled() || !image)
   1033         return;
   1034 
   1035     if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
   1036         // Just do a scale.
   1037         drawImage(image, dest, srcRect, op);
   1038         return;
   1039     }
   1040 
   1041     if (useLowQualityScale) {
   1042         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
   1043         setImageInterpolationQuality(InterpolationLow);
   1044         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op);
   1045         setImageInterpolationQuality(previousInterpolationQuality);
   1046     } else {
   1047         image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op);
   1048     }
   1049 }
   1050 
   1051 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& p, CompositeOperator op, BlendMode blendMode)
   1052 {
   1053     if (!image)
   1054         return;
   1055     drawImageBuffer(image, FloatRect(IntRect(p, image->logicalSize())), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode);
   1056 }
   1057 
   1058 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& r, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
   1059 {
   1060     if (!image)
   1061         return;
   1062     drawImageBuffer(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->logicalSize())), op, blendMode, useLowQualityScale);
   1063 }
   1064 
   1065 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode)
   1066 {
   1067     drawImageBuffer(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, blendMode);
   1068 }
   1069 
   1070 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
   1071 {
   1072     drawImageBuffer(image, FloatRect(dest), FloatRect(srcRect), op, blendMode, useLowQualityScale);
   1073 }
   1074 
   1075 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest)
   1076 {
   1077     if (!image)
   1078         return;
   1079     drawImageBuffer(image, dest, FloatRect(IntRect(IntPoint(), image->logicalSize())));
   1080 }
   1081 
   1082 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
   1083 {
   1084     if (paintingDisabled() || !image)
   1085         return;
   1086 
   1087     if (useLowQualityScale) {
   1088         InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
   1089         setImageInterpolationQuality(InterpolationLow);
   1090         image->draw(this, dest, src, op, blendMode, useLowQualityScale);
   1091         setImageInterpolationQuality(previousInterpolationQuality);
   1092     } else {
   1093         image->draw(this, dest, src, op, blendMode, useLowQualityScale);
   1094     }
   1095 }
   1096 
   1097 void GraphicsContext::writePixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888)
   1098 {
   1099     if (paintingDisabled())
   1100         return;
   1101 
   1102     m_canvas->writePixels(bitmap, x, y, config8888);
   1103 
   1104     if (m_trackOpaqueRegion) {
   1105         SkRect rect = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
   1106         SkPaint paint;
   1107 
   1108         paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   1109         m_opaqueRegion.didDrawRect(this, rect, paint, &bitmap);
   1110     }
   1111 }
   1112 
   1113 void GraphicsContext::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint)
   1114 {
   1115     if (paintingDisabled())
   1116         return;
   1117 
   1118     m_canvas->drawBitmap(bitmap, left, top, paint);
   1119 
   1120     if (m_trackOpaqueRegion) {
   1121         SkRect rect = SkRect::MakeXYWH(left, top, bitmap.width(), bitmap.height());
   1122         m_opaqueRegion.didDrawRect(this, rect, *paint, &bitmap);
   1123     }
   1124 }
   1125 
   1126 void GraphicsContext::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
   1127     const SkRect& dst, const SkPaint* paint)
   1128 {
   1129     if (paintingDisabled())
   1130         return;
   1131 
   1132     m_canvas->drawBitmapRectToRect(bitmap, src, dst, paint);
   1133 
   1134     if (m_trackOpaqueRegion)
   1135         m_opaqueRegion.didDrawRect(this, dst, *paint, &bitmap);
   1136 }
   1137 
   1138 void GraphicsContext::drawOval(const SkRect& oval, const SkPaint& paint)
   1139 {
   1140     if (paintingDisabled())
   1141         return;
   1142 
   1143     m_canvas->drawOval(oval, paint);
   1144 
   1145     if (m_trackOpaqueRegion)
   1146         m_opaqueRegion.didDrawBounded(this, oval, paint);
   1147 }
   1148 
   1149 void GraphicsContext::drawPath(const SkPath& path, const SkPaint& paint)
   1150 {
   1151     if (paintingDisabled())
   1152         return;
   1153 
   1154     m_canvas->drawPath(path, paint);
   1155 
   1156     if (m_trackOpaqueRegion)
   1157         m_opaqueRegion.didDrawPath(this, path, paint);
   1158 }
   1159 
   1160 void GraphicsContext::drawRect(const SkRect& rect, const SkPaint& paint)
   1161 {
   1162     if (paintingDisabled())
   1163         return;
   1164 
   1165     m_canvas->drawRect(rect, paint);
   1166 
   1167     if (m_trackOpaqueRegion)
   1168         m_opaqueRegion.didDrawRect(this, rect, paint, 0);
   1169 }
   1170 
   1171 void GraphicsContext::didDrawRect(const SkRect& rect, const SkPaint& paint, const SkBitmap* bitmap)
   1172 {
   1173     if (m_trackOpaqueRegion)
   1174         m_opaqueRegion.didDrawRect(this, rect, paint, bitmap);
   1175 }
   1176 
   1177 void GraphicsContext::drawPosText(const void* text, size_t byteLength,
   1178     const SkPoint pos[],  const SkRect& textRect, const SkPaint& paint)
   1179 {
   1180     if (paintingDisabled())
   1181         return;
   1182 
   1183     m_canvas->drawPosText(text, byteLength, pos, paint);
   1184     didDrawTextInRect(textRect);
   1185 
   1186     // FIXME: compute bounds for positioned text.
   1187     if (m_trackOpaqueRegion)
   1188         m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke);
   1189 }
   1190 
   1191 void GraphicsContext::drawPosTextH(const void* text, size_t byteLength,
   1192     const SkScalar xpos[], SkScalar constY,  const SkRect& textRect, const SkPaint& paint)
   1193 {
   1194     if (paintingDisabled())
   1195         return;
   1196 
   1197     m_canvas->drawPosTextH(text, byteLength, xpos, constY, paint);
   1198     didDrawTextInRect(textRect);
   1199 
   1200     // FIXME: compute bounds for positioned text.
   1201     if (m_trackOpaqueRegion)
   1202         m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke);
   1203 }
   1204 
   1205 void GraphicsContext::drawTextOnPath(const void* text, size_t byteLength,
   1206     const SkPath& path,  const SkRect& textRect, const SkMatrix* matrix, const SkPaint& paint)
   1207 {
   1208     if (paintingDisabled())
   1209         return;
   1210 
   1211     m_canvas->drawTextOnPath(text, byteLength, path, matrix, paint);
   1212     didDrawTextInRect(textRect);
   1213 
   1214     // FIXME: compute bounds for positioned text.
   1215     if (m_trackOpaqueRegion)
   1216         m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke);
   1217 }
   1218 
   1219 void GraphicsContext::fillPath(const Path& pathToFill)
   1220 {
   1221     if (paintingDisabled() || pathToFill.isEmpty())
   1222         return;
   1223 
   1224     // Use const_cast and temporarily modify the fill type instead of copying the path.
   1225     SkPath& path = const_cast<SkPath&>(pathToFill.skPath());
   1226     SkPath::FillType previousFillType = path.getFillType();
   1227 
   1228     SkPath::FillType temporaryFillType = m_state->m_fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
   1229     path.setFillType(temporaryFillType);
   1230 
   1231     SkPaint paint;
   1232     setupPaintForFilling(&paint);
   1233     drawPath(path, paint);
   1234 
   1235     path.setFillType(previousFillType);
   1236 }
   1237 
   1238 void GraphicsContext::fillRect(const FloatRect& rect)
   1239 {
   1240     if (paintingDisabled())
   1241         return;
   1242 
   1243     SkRect r = rect;
   1244 
   1245     SkPaint paint;
   1246     setupPaintForFilling(&paint);
   1247     drawRect(r, paint);
   1248 }
   1249 
   1250 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
   1251 {
   1252     if (paintingDisabled())
   1253         return;
   1254 
   1255     SkRect r = rect;
   1256     SkPaint paint;
   1257     setupPaintCommon(&paint);
   1258     paint.setColor(color.rgb());
   1259     drawRect(r, paint);
   1260 }
   1261 
   1262 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
   1263     const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
   1264 {
   1265     if (paintingDisabled())
   1266         return;
   1267 
   1268     if (topLeft.width() + topRight.width() > rect.width()
   1269             || bottomLeft.width() + bottomRight.width() > rect.width()
   1270             || topLeft.height() + bottomLeft.height() > rect.height()
   1271             || topRight.height() + bottomRight.height() > rect.height()) {
   1272         // Not all the radii fit, return a rect. This matches the behavior of
   1273         // Path::createRoundedRectangle. Without this we attempt to draw a round
   1274         // shadow for a square box.
   1275         fillRect(rect, color);
   1276         return;
   1277     }
   1278 
   1279     SkVector radii[4];
   1280     setRadii(radii, topLeft, topRight, bottomRight, bottomLeft);
   1281 
   1282     SkRRect rr;
   1283     rr.setRectRadii(rect, radii);
   1284 
   1285     SkPaint paint;
   1286     setupPaintForFilling(&paint);
   1287     paint.setColor(color.rgb());
   1288 
   1289     m_canvas->drawRRect(rr, paint);
   1290 
   1291     if (m_trackOpaqueRegion)
   1292         m_opaqueRegion.didDrawBounded(this, rr.getBounds(), paint);
   1293 }
   1294 
   1295 void GraphicsContext::fillEllipse(const FloatRect& ellipse)
   1296 {
   1297     if (paintingDisabled())
   1298         return;
   1299 
   1300     SkRect rect = ellipse;
   1301     SkPaint paint;
   1302     setupPaintForFilling(&paint);
   1303     drawOval(rect, paint);
   1304 }
   1305 
   1306 void GraphicsContext::strokePath(const Path& pathToStroke)
   1307 {
   1308     if (paintingDisabled() || pathToStroke.isEmpty())
   1309         return;
   1310 
   1311     const SkPath& path = pathToStroke.skPath();
   1312     SkPaint paint;
   1313     setupPaintForStroking(&paint);
   1314     drawPath(path, paint);
   1315 }
   1316 
   1317 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
   1318 {
   1319     if (paintingDisabled())
   1320         return;
   1321 
   1322     SkPaint paint;
   1323     setupPaintForStroking(&paint);
   1324     paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
   1325     // strokerect has special rules for CSS when the rect is degenerate:
   1326     // if width==0 && height==0, do nothing
   1327     // if width==0 || height==0, then just draw line for the other dimension
   1328     SkRect r(rect);
   1329     bool validW = r.width() > 0;
   1330     bool validH = r.height() > 0;
   1331     if (validW && validH) {
   1332         drawRect(r, paint);
   1333     } else if (validW || validH) {
   1334         // we are expected to respect the lineJoin, so we can't just call
   1335         // drawLine -- we have to create a path that doubles back on itself.
   1336         SkPath path;
   1337         path.moveTo(r.fLeft, r.fTop);
   1338         path.lineTo(r.fRight, r.fBottom);
   1339         path.close();
   1340         drawPath(path, paint);
   1341     }
   1342 }
   1343 
   1344 void GraphicsContext::strokeEllipse(const FloatRect& ellipse)
   1345 {
   1346     if (paintingDisabled())
   1347         return;
   1348 
   1349     SkRect rect(ellipse);
   1350     SkPaint paint;
   1351     setupPaintForStroking(&paint);
   1352     drawOval(rect, paint);
   1353 }
   1354 
   1355 void GraphicsContext::clipRoundedRect(const RoundedRect& rect)
   1356 {
   1357     if (paintingDisabled())
   1358         return;
   1359 
   1360     SkVector radii[4];
   1361     RoundedRect::Radii wkRadii = rect.radii();
   1362     setRadii(radii, wkRadii.topLeft(), wkRadii.topRight(), wkRadii.bottomRight(), wkRadii.bottomLeft());
   1363 
   1364     SkRRect r;
   1365     r.setRectRadii(rect.rect(), radii);
   1366 
   1367     clipRRect(r, AntiAliased);
   1368 }
   1369 
   1370 void GraphicsContext::clipOut(const Path& pathToClip)
   1371 {
   1372     if (paintingDisabled())
   1373         return;
   1374 
   1375     // Use const_cast and temporarily toggle the inverse fill type instead of copying the path.
   1376     SkPath& path = const_cast<SkPath&>(pathToClip.skPath());
   1377     path.toggleInverseFillType();
   1378     clipPath(path, AntiAliased);
   1379     path.toggleInverseFillType();
   1380 }
   1381 
   1382 void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
   1383 {
   1384     if (paintingDisabled() || pathToClip.isEmpty())
   1385         return;
   1386 
   1387     // Use const_cast and temporarily modify the fill type instead of copying the path.
   1388     SkPath& path = const_cast<SkPath&>(pathToClip.skPath());
   1389     SkPath::FillType previousFillType = path.getFillType();
   1390 
   1391     SkPath::FillType temporaryFillType = clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
   1392     path.setFillType(temporaryFillType);
   1393     clipPath(path, AntiAliased);
   1394 
   1395     path.setFillType(previousFillType);
   1396 }
   1397 
   1398 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
   1399 {
   1400     if (paintingDisabled())
   1401         return;
   1402 
   1403     if (numPoints <= 1)
   1404         return;
   1405 
   1406     SkPath path;
   1407     setPathFromConvexPoints(&path, numPoints, points);
   1408     clipPath(path, antialiased ? AntiAliased : NotAntiAliased);
   1409 }
   1410 
   1411 void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect)
   1412 {
   1413     if (paintingDisabled())
   1414         return;
   1415 
   1416     if (!rect.isRounded()) {
   1417         clipOut(rect.rect());
   1418         return;
   1419     }
   1420 
   1421     Path path;
   1422     path.addRoundedRect(rect);
   1423     clipOut(path);
   1424 }
   1425 
   1426 void GraphicsContext::canvasClip(const Path& pathToClip, WindRule clipRule)
   1427 {
   1428     if (paintingDisabled())
   1429         return;
   1430 
   1431     // Use const_cast and temporarily modify the fill type instead of copying the path.
   1432     SkPath& path = const_cast<SkPath&>(pathToClip.skPath());
   1433     SkPath::FillType previousFillType = path.getFillType();
   1434 
   1435     SkPath::FillType temporaryFillType = clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
   1436     path.setFillType(temporaryFillType);
   1437     clipPath(path);
   1438 
   1439     path.setFillType(previousFillType);
   1440 }
   1441 
   1442 bool GraphicsContext::clipRect(const SkRect& rect, AntiAliasingMode aa, SkRegion::Op op)
   1443 {
   1444     if (paintingDisabled())
   1445         return false;
   1446 
   1447     realizeSave(SkCanvas::kClip_SaveFlag);
   1448 
   1449     return m_canvas->clipRect(rect, op, aa == AntiAliased);
   1450 }
   1451 
   1452 bool GraphicsContext::clipPath(const SkPath& path, AntiAliasingMode aa, SkRegion::Op op)
   1453 {
   1454     if (paintingDisabled())
   1455         return false;
   1456 
   1457     realizeSave(SkCanvas::kClip_SaveFlag);
   1458 
   1459     return m_canvas->clipPath(path, op, aa == AntiAliased);
   1460 }
   1461 
   1462 bool GraphicsContext::clipRRect(const SkRRect& rect, AntiAliasingMode aa, SkRegion::Op op)
   1463 {
   1464     if (paintingDisabled())
   1465         return false;
   1466 
   1467     realizeSave(SkCanvas::kClip_SaveFlag);
   1468 
   1469     return m_canvas->clipRRect(rect, op, aa == AntiAliased);
   1470 }
   1471 
   1472 void GraphicsContext::rotate(float angleInRadians)
   1473 {
   1474     if (paintingDisabled())
   1475         return;
   1476 
   1477     realizeSave(SkCanvas::kMatrix_SaveFlag);
   1478 
   1479     m_canvas->rotate(WebCoreFloatToSkScalar(angleInRadians * (180.0f / 3.14159265f)));
   1480 }
   1481 
   1482 void GraphicsContext::translate(float w, float h)
   1483 {
   1484     if (paintingDisabled())
   1485         return;
   1486 
   1487     realizeSave(SkCanvas::kMatrix_SaveFlag);
   1488 
   1489     m_canvas->translate(WebCoreFloatToSkScalar(w), WebCoreFloatToSkScalar(h));
   1490 }
   1491 
   1492 void GraphicsContext::scale(const FloatSize& size)
   1493 {
   1494     if (paintingDisabled())
   1495         return;
   1496 
   1497     realizeSave(SkCanvas::kMatrix_SaveFlag);
   1498 
   1499     m_canvas->scale(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height()));
   1500 }
   1501 
   1502 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
   1503 {
   1504     if (paintingDisabled())
   1505         return;
   1506 
   1507     SkAutoDataUnref url(SkData::NewWithCString(link.string().utf8().data()));
   1508     SkAnnotateRectWithURL(m_canvas, destRect, url.get());
   1509 }
   1510 
   1511 void GraphicsContext::setURLFragmentForRect(const String& destName, const IntRect& rect)
   1512 {
   1513     if (paintingDisabled())
   1514         return;
   1515 
   1516     SkAutoDataUnref skDestName(SkData::NewWithCString(destName.utf8().data()));
   1517     SkAnnotateLinkToDestination(m_canvas, rect, skDestName.get());
   1518 }
   1519 
   1520 void GraphicsContext::addURLTargetAtPoint(const String& name, const IntPoint& pos)
   1521 {
   1522     if (paintingDisabled())
   1523         return;
   1524 
   1525     SkAutoDataUnref nameData(SkData::NewWithCString(name.utf8().data()));
   1526     SkAnnotateNamedDestination(m_canvas, SkPoint::Make(pos.x(), pos.y()), nameData);
   1527 }
   1528 
   1529 AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
   1530 {
   1531     if (paintingDisabled())
   1532         return AffineTransform();
   1533 
   1534     const SkMatrix& m = getTotalMatrix();
   1535     return AffineTransform(SkScalarToDouble(m.getScaleX()),
   1536                            SkScalarToDouble(m.getSkewY()),
   1537                            SkScalarToDouble(m.getSkewX()),
   1538                            SkScalarToDouble(m.getScaleY()),
   1539                            SkScalarToDouble(m.getTranslateX()),
   1540                            SkScalarToDouble(m.getTranslateY()));
   1541 }
   1542 
   1543 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, CompositeOperator op)
   1544 {
   1545     if (paintingDisabled())
   1546         return;
   1547 
   1548     CompositeOperator previousOperator = compositeOperation();
   1549     setCompositeOperation(op);
   1550     fillRect(rect, color);
   1551     setCompositeOperation(previousOperator);
   1552 }
   1553 
   1554 void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color)
   1555 {
   1556     if (rect.isRounded())
   1557         fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color);
   1558     else
   1559         fillRect(rect.rect(), color);
   1560 }
   1561 
   1562 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color)
   1563 {
   1564     if (paintingDisabled())
   1565         return;
   1566 
   1567     Path path;
   1568     path.addRect(rect);
   1569 
   1570     if (!roundedHoleRect.radii().isZero())
   1571         path.addRoundedRect(roundedHoleRect);
   1572     else
   1573         path.addRect(roundedHoleRect.rect());
   1574 
   1575     WindRule oldFillRule = fillRule();
   1576     Color oldFillColor = fillColor();
   1577 
   1578     setFillRule(RULE_EVENODD);
   1579     setFillColor(color);
   1580 
   1581     fillPath(path);
   1582 
   1583     setFillRule(oldFillRule);
   1584     setFillColor(oldFillColor);
   1585 }
   1586 
   1587 void GraphicsContext::clearRect(const FloatRect& rect)
   1588 {
   1589     if (paintingDisabled())
   1590         return;
   1591 
   1592     SkRect r = rect;
   1593     SkPaint paint;
   1594     setupPaintForFilling(&paint);
   1595     paint.setXfermodeMode(SkXfermode::kClear_Mode);
   1596     drawRect(r, paint);
   1597 }
   1598 
   1599 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
   1600 {
   1601     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
   1602     // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
   1603     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
   1604     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
   1605     if (penStyle == DottedStroke || penStyle == DashedStroke) {
   1606         if (p1.x() == p2.x()) {
   1607             p1.setY(p1.y() + strokeWidth);
   1608             p2.setY(p2.y() - strokeWidth);
   1609         } else {
   1610             p1.setX(p1.x() + strokeWidth);
   1611             p2.setX(p2.x() - strokeWidth);
   1612         }
   1613     }
   1614 
   1615     if (static_cast<int>(strokeWidth) % 2) { //odd
   1616         if (p1.x() == p2.x()) {
   1617             // We're a vertical line.  Adjust our x.
   1618             p1.setX(p1.x() + 0.5f);
   1619             p2.setX(p2.x() + 0.5f);
   1620         } else {
   1621             // We're a horizontal line. Adjust our y.
   1622             p1.setY(p1.y() + 0.5f);
   1623             p2.setY(p2.y() + 0.5f);
   1624         }
   1625     }
   1626 }
   1627 
   1628 static bool scalesMatch(AffineTransform a, AffineTransform b)
   1629 {
   1630     return a.xScale() == b.xScale() && a.yScale() == b.yScale();
   1631 }
   1632 
   1633 PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size, bool hasAlpha) const
   1634 {
   1635     // Make the buffer larger if the context's transform is scaling it so we need a higher
   1636     // resolution than one pixel per unit. Also set up a corresponding scale factor on the
   1637     // graphics context.
   1638 
   1639     AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
   1640     IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));
   1641 
   1642     OwnPtr<ImageBuffer> buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, this, hasAlpha);
   1643     if (!buffer)
   1644         return nullptr;
   1645 
   1646     buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(),
   1647         static_cast<float>(scaledSize.height()) / size.height()));
   1648 
   1649     return buffer.release();
   1650 }
   1651 
   1652 bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const
   1653 {
   1654     GraphicsContext* bufferContext = buffer->context();
   1655 
   1656     return scalesMatch(getCTM(), bufferContext->getCTM()) && m_accelerated == bufferContext->isAccelerated();
   1657 }
   1658 
   1659 void GraphicsContext::addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
   1660 {
   1661     SkIRect ir;
   1662     int rx = SkMin32(SkScalarRound(rect.width()), size.width());
   1663     int ry = SkMin32(SkScalarRound(rect.height()), size.height());
   1664 
   1665     ir.set(-rx, -ry, rx, ry);
   1666     switch (startAngle) {
   1667     case 0:
   1668         ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
   1669         break;
   1670     case 90:
   1671         ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
   1672         break;
   1673     case 180:
   1674         ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
   1675         break;
   1676     case 270:
   1677         ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
   1678         break;
   1679     default:
   1680         ASSERT(0);
   1681     }
   1682 
   1683     SkRect r;
   1684     r.set(ir);
   1685     path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
   1686 }
   1687 
   1688 void GraphicsContext::setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points)
   1689 {
   1690     path->incReserve(numPoints);
   1691     path->moveTo(WebCoreFloatToSkScalar(points[0].x()),
   1692                  WebCoreFloatToSkScalar(points[0].y()));
   1693     for (size_t i = 1; i < numPoints; ++i) {
   1694         path->lineTo(WebCoreFloatToSkScalar(points[i].x()),
   1695                      WebCoreFloatToSkScalar(points[i].y()));
   1696     }
   1697 
   1698     /*  The code used to just blindly call this
   1699             path->setIsConvex(true);
   1700         But webkit can sometimes send us non-convex 4-point values, so we mark the path's
   1701         convexity as unknown, so it will get computed by skia at draw time.
   1702         See crbug.com 108605
   1703     */
   1704     SkPath::Convexity convexity = SkPath::kConvex_Convexity;
   1705     if (numPoints == 4)
   1706         convexity = SkPath::kUnknown_Convexity;
   1707     path->setConvexity(convexity);
   1708 }
   1709 
   1710 void GraphicsContext::setupPaintCommon(SkPaint* paint) const
   1711 {
   1712 #if defined(SK_DEBUG)
   1713     {
   1714         SkPaint defaultPaint;
   1715         SkASSERT(*paint == defaultPaint);
   1716     }
   1717 #endif
   1718 
   1719     paint->setAntiAlias(m_state->m_shouldAntialias);
   1720     paint->setXfermodeMode(m_state->m_xferMode);
   1721     paint->setLooper(m_state->m_looper.get());
   1722 }
   1723 
   1724 void GraphicsContext::drawOuterPath(const SkPath& path, SkPaint& paint, int width)
   1725 {
   1726 #if OS(DARWIN)
   1727     paint.setAlpha(64);
   1728     paint.setStrokeWidth(width);
   1729     paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref();
   1730 #else
   1731     paint.setStrokeWidth(1);
   1732     paint.setPathEffect(new SkCornerPathEffect(1))->unref();
   1733 #endif
   1734     drawPath(path, paint);
   1735 }
   1736 
   1737 void GraphicsContext::drawInnerPath(const SkPath& path, SkPaint& paint, int width)
   1738 {
   1739 #if OS(DARWIN)
   1740     paint.setAlpha(128);
   1741     paint.setStrokeWidth(width * 0.5f);
   1742     drawPath(path, paint);
   1743 #endif
   1744 }
   1745 
   1746 void GraphicsContext::setRadii(SkVector* radii, IntSize topLeft, IntSize topRight, IntSize bottomRight, IntSize bottomLeft)
   1747 {
   1748     radii[SkRRect::kUpperLeft_Corner].set(SkIntToScalar(topLeft.width()),
   1749         SkIntToScalar(topLeft.height()));
   1750     radii[SkRRect::kUpperRight_Corner].set(SkIntToScalar(topRight.width()),
   1751         SkIntToScalar(topRight.height()));
   1752     radii[SkRRect::kLowerRight_Corner].set(SkIntToScalar(bottomRight.width()),
   1753         SkIntToScalar(bottomRight.height()));
   1754     radii[SkRRect::kLowerLeft_Corner].set(SkIntToScalar(bottomLeft.width()),
   1755         SkIntToScalar(bottomLeft.height()));
   1756 }
   1757 
   1758 #if OS(DARWIN)
   1759 CGColorSpaceRef deviceRGBColorSpaceRef()
   1760 {
   1761     static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
   1762     return deviceSpace;
   1763 }
   1764 #else
   1765 void GraphicsContext::draw2xMarker(SkBitmap* bitmap, int index)
   1766 {
   1767     const SkPMColor lineColor = lineColors(index);
   1768     const SkPMColor antiColor1 = antiColors1(index);
   1769     const SkPMColor antiColor2 = antiColors2(index);
   1770 
   1771     uint32_t* row1 = bitmap->getAddr32(0, 0);
   1772     uint32_t* row2 = bitmap->getAddr32(0, 1);
   1773     uint32_t* row3 = bitmap->getAddr32(0, 2);
   1774     uint32_t* row4 = bitmap->getAddr32(0, 3);
   1775 
   1776     // Pattern: X0o   o0X0o   o0
   1777     //          XX0o o0XXX0o o0X
   1778     //           o0XXX0o o0XXX0o
   1779     //            o0X0o   o0X0o
   1780     const SkPMColor row1Color[] = { lineColor, antiColor1, antiColor2, 0,          0,         0,          antiColor2, antiColor1 };
   1781     const SkPMColor row2Color[] = { lineColor, lineColor,  antiColor1, antiColor2, 0,         antiColor2, antiColor1, lineColor };
   1782     const SkPMColor row3Color[] = { 0,         antiColor2, antiColor1, lineColor,  lineColor, lineColor,  antiColor1, antiColor2 };
   1783     const SkPMColor row4Color[] = { 0,         0,          antiColor2, antiColor1, lineColor, antiColor1, antiColor2, 0 };
   1784 
   1785     for (int x = 0; x < bitmap->width() + 8; x += 8) {
   1786         int count = std::min(bitmap->width() - x, 8);
   1787         if (count > 0) {
   1788             memcpy(row1 + x, row1Color, count * sizeof(SkPMColor));
   1789             memcpy(row2 + x, row2Color, count * sizeof(SkPMColor));
   1790             memcpy(row3 + x, row3Color, count * sizeof(SkPMColor));
   1791             memcpy(row4 + x, row4Color, count * sizeof(SkPMColor));
   1792         }
   1793     }
   1794 }
   1795 
   1796 void GraphicsContext::draw1xMarker(SkBitmap* bitmap, int index)
   1797 {
   1798     const uint32_t lineColor = lineColors(index);
   1799     const uint32_t antiColor = antiColors2(index);
   1800 
   1801     // Pattern: X o   o X o   o X
   1802     //            o X o   o X o
   1803     uint32_t* row1 = bitmap->getAddr32(0, 0);
   1804     uint32_t* row2 = bitmap->getAddr32(0, 1);
   1805     for (int x = 0; x < bitmap->width(); x++) {
   1806         switch (x % 4) {
   1807         case 0:
   1808             row1[x] = lineColor;
   1809             break;
   1810         case 1:
   1811             row1[x] = antiColor;
   1812             row2[x] = antiColor;
   1813             break;
   1814         case 2:
   1815             row2[x] = lineColor;
   1816             break;
   1817         case 3:
   1818             row1[x] = antiColor;
   1819             row2[x] = antiColor;
   1820             break;
   1821         }
   1822     }
   1823 }
   1824 
   1825 const SkPMColor GraphicsContext::lineColors(int index)
   1826 {
   1827     static const SkPMColor colors[] = {
   1828         SkPreMultiplyARGB(0xFF, 0xFF, 0x00, 0x00), // Opaque red.
   1829         SkPreMultiplyARGB(0xFF, 0xC0, 0xC0, 0xC0) // Opaque gray.
   1830     };
   1831 
   1832     return colors[index];
   1833 }
   1834 
   1835 const SkPMColor GraphicsContext::antiColors1(int index)
   1836 {
   1837     static const SkPMColor colors[] = {
   1838         SkPreMultiplyARGB(0xB0, 0xFF, 0x00, 0x00), // Semitransparent red.
   1839         SkPreMultiplyARGB(0xB0, 0xC0, 0xC0, 0xC0)  // Semitransparent gray.
   1840     };
   1841 
   1842     return colors[index];
   1843 }
   1844 
   1845 const SkPMColor GraphicsContext::antiColors2(int index)
   1846 {
   1847     static const SkPMColor colors[] = {
   1848         SkPreMultiplyARGB(0x60, 0xFF, 0x00, 0x00), // More transparent red
   1849         SkPreMultiplyARGB(0x60, 0xC0, 0xC0, 0xC0)  // More transparent gray
   1850     };
   1851 
   1852     return colors[index];
   1853 }
   1854 #endif
   1855 
   1856 void GraphicsContext::setupShader(SkPaint* paint, Gradient* grad, Pattern* pat, SkColor color) const
   1857 {
   1858     RefPtr<SkShader> shader;
   1859 
   1860     if (grad) {
   1861         shader = grad->shader();
   1862         color = SK_ColorBLACK;
   1863     } else if (pat) {
   1864         shader = pat->shader();
   1865         color = SK_ColorBLACK;
   1866         paint->setFilterBitmap(imageInterpolationQuality() != InterpolationNone);
   1867     }
   1868 
   1869     paint->setColor(m_state->applyAlpha(color));
   1870     paint->setShader(shader.get());
   1871 }
   1872 
   1873 
   1874 void GraphicsContext::applyClipFromImage(const SkRect& rect, const SkBitmap& imageBuffer)
   1875 {
   1876     if (paintingDisabled())
   1877         return;
   1878 
   1879     // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
   1880     // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
   1881     SkPaint paint;
   1882     paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
   1883     realizeSave(SkCanvas::kMatrixClip_SaveFlag);
   1884     m_canvas->save(SkCanvas::kMatrix_SaveFlag);
   1885     m_canvas->resetMatrix();
   1886     m_canvas->drawBitmapRect(imageBuffer, 0, rect, &paint);
   1887     m_canvas->restore();
   1888 }
   1889 
   1890 void GraphicsContext::didDrawTextInRect(const SkRect& textRect)
   1891 {
   1892     if (m_trackTextRegion) {
   1893         TRACE_EVENT0("skia", "PlatformContextSkia::trackTextRegion");
   1894         m_textRegion.join(textRect);
   1895     }
   1896 }
   1897 
   1898 }
   1899