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