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