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