Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: sky/engine/platform/graphics/GraphicsContext.cpp.orig

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

Powered by Google App Engine
This is Rietveld 408576698