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