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