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