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