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
57using namespace std;
58using blink::WebBlendMode;
59
60namespace WebCore {
61
62namespace {
63
64class CompatibleImageBufferSurface : public ImageBufferSurface {
65    WTF_MAKE_NONCOPYABLE(CompatibleImageBufferSurface); WTF_MAKE_FAST_ALLOCATED;
66public:
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
87private:
88    OwnPtr<SkCanvas> m_canvas;
89};
90
91} // unnamed namespace
92
93struct 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
100struct 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
113GraphicsContext::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
133GraphicsContext::~GraphicsContext()
134{
135    ASSERT(m_stateStack.size() == 1);
136    ASSERT(!m_annotationCount);
137    ASSERT(!m_layerCount);
138    ASSERT(m_recordingStateStack.isEmpty());
139}
140
141const SkBitmap* GraphicsContext::bitmap() const
142{
143    TRACE_EVENT0("skia", "GraphicsContext::bitmap");
144    return &m_canvas->getDevice()->accessBitmap(false);
145}
146
147const SkBitmap& GraphicsContext::layerBitmap(AccessMode access) const
148{
149    return m_canvas->getTopDevice()->accessBitmap(access == ReadWrite);
150}
151
152void 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
164void 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
183void 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
197void GraphicsContext::restoreLayer()
198{
199    if (paintingDisabled())
200        return;
201
202    m_canvas->restore();
203    if (m_trackOpaqueRegion)
204        m_opaqueRegion.popCanvasLayer(this);
205}
206
207void 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
228void 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
241void 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
248void 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
262void 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
276void 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
283void 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
297void 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
311void 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
329void GraphicsContext::setDrawLooper(const DrawLooper& drawLooper)
330{
331    if (paintingDisabled())
332        return;
333
334    m_state->m_looper = drawLooper.skDrawLooper();
335}
336
337void GraphicsContext::clearDrawLooper()
338{
339    if (paintingDisabled())
340        return;
341
342    m_state->m_looper.clear();
343}
344
345bool GraphicsContext::hasShadow() const
346{
347    return !!m_state->m_looper;
348}
349
350int 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
360bool GraphicsContext::getClipBounds(SkRect* bounds) const
361{
362    if (paintingDisabled())
363        return false;
364    return m_canvas->getClipBounds(bounds);
365}
366
367bool 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
379SkMatrix 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
394bool GraphicsContext::isPrintingDevice() const
395{
396    if (paintingDisabled())
397        return false;
398    return m_canvas->getTopDevice()->getDeviceCapabilities() & SkBaseDevice::kVector_Capability;
399}
400
401void GraphicsContext::adjustTextRenderMode(SkPaint* paint)
402{
403    if (paintingDisabled())
404        return;
405
406    if (!paint->isLCDRenderText())
407        return;
408
409    paint->setLCDRenderText(couldUseLCDRenderedText());
410}
411
412bool 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
424void 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
431SkColorFilter* GraphicsContext::colorFilter()
432{
433    return m_state->m_colorFilter.get();
434}
435
436void 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
444bool 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
452void 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
462bool 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
472void GraphicsContext::beginTransparencyLayer(float opacity, const FloatRect* bounds)
473{
474    beginLayer(opacity, m_state->m_compositeOperator, bounds);
475}
476
477void 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
505void 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
518void 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
540PassRefPtr<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
554bool GraphicsContext::isRecording() const
555{
556    return !m_recordingStateStack.isEmpty();
557}
558
559void 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
578void 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
588float 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
601void 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.
625void 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
642void 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
657void 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
685static 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
699void 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.
750void 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
802void 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
929void 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.
966void 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
1001void 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
1009void 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
1017void 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
1057void 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
1065void 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
1072void 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
1079void 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
1084void 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
1089void GraphicsContext::drawImage(Image* image, const FloatRect& dest)
1090{
1091    if (!image)
1092        return;
1093    drawImage(image, dest, FloatRect(IntRect(IntPoint(), image->size())));
1094}
1095
1096void 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
1113void 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
1128void 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
1150void 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
1157void 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
1164void 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
1169void 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
1174void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest)
1175{
1176    if (!image)
1177        return;
1178    drawImageBuffer(image, dest, FloatRect(IntRect(IntPoint(), image->size())));
1179}
1180
1181void 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
1196void 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
1212void 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
1225void 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
1239void 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
1250void 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
1261void 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
1272void 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
1278void 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
1292void 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
1306void 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
1320void 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
1339void 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
1351void 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
1363void 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
1396void 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
1407void 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
1418void 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
1445void 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
1456void 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
1471void 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
1483void 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
1499void 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
1512void 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
1527void 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
1543bool 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
1553bool 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
1563bool 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
1573void 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
1583void 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
1593void 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
1603void 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
1612void 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
1621void 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
1630AffineTransform 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
1644void 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
1655void 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
1663void 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
1688void 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
1700void 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
1729PassOwnPtr<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
1751void 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
1780void 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
1802void 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
1822void 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
1835void 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
1844void 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
1856PassRefPtr<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)
1876CGColorSpaceRef PLATFORM_EXPORT deviceRGBColorSpaceRef()
1877{
1878    static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
1879    return deviceSpace;
1880}
1881#else
1882void 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
1913void 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
1942const 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
1952const 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
1962const 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
1973void 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
1994void 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