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