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