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