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