2 * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2013 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "platform/graphics/GraphicsContext.h"
30 #include "platform/geometry/IntRect.h"
31 #include "platform/geometry/RoundedRect.h"
32 #include "platform/graphics/BitmapImage.h"
33 #include "platform/graphics/DisplayList.h"
34 #include "platform/graphics/Gradient.h"
35 #include "platform/graphics/ImageBuffer.h"
36 #include "platform/text/BidiResolver.h"
37 #include "platform/text/TextRunIterator.h"
38 #include "platform/weborigin/KURL.h"
39 #include "third_party/skia/include/core/SkAnnotation.h"
40 #include "third_party/skia/include/core/SkColorFilter.h"
41 #include "third_party/skia/include/core/SkData.h"
42 #include "third_party/skia/include/core/SkDevice.h"
43 #include "third_party/skia/include/core/SkPicture.h"
44 #include "third_party/skia/include/core/SkRRect.h"
45 #include "third_party/skia/include/core/SkRefCnt.h"
46 #include "third_party/skia/include/effects/SkBlurMaskFilter.h"
47 #include "third_party/skia/include/effects/SkCornerPathEffect.h"
48 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
49 #include "third_party/skia/include/gpu/GrRenderTarget.h"
50 #include "third_party/skia/include/gpu/GrTexture.h"
51 #include "wtf/Assertions.h"
52 #include "wtf/MathExtras.h"
55 #include <ApplicationServices/ApplicationServices.h>
59 using blink::WebBlendMode;
65 class CompatibleImageBufferSurface : public ImageBufferSurface {
66 WTF_MAKE_NONCOPYABLE(CompatibleImageBufferSurface); WTF_MAKE_FAST_ALLOCATED;
68 CompatibleImageBufferSurface(PassRefPtr<SkBaseDevice> device, const IntSize& size, OpacityMode opacityMode)
69 : ImageBufferSurface(size, opacityMode)
71 m_canvas = adoptPtr(new SkCanvas(device.get())); // Takes a ref on device
73 virtual ~CompatibleImageBufferSurface() { }
75 virtual SkCanvas* canvas() const OVERRIDE { return m_canvas.get(); }
76 virtual bool isValid() const OVERRIDE { return m_canvas; }
77 virtual bool isAccelerated() const OVERRIDE { return isValid() && m_canvas->getTopDevice()->accessRenderTarget(); }
78 virtual Platform3DObject getBackingTexture() const OVERRIDE
80 ASSERT(isAccelerated());
81 GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget();
83 return renderTarget->asTexture()->getTextureHandle();
89 OwnPtr<SkCanvas> m_canvas;
92 } // unnamed namespace
94 struct GraphicsContext::CanvasSaveState {
95 CanvasSaveState(unsigned mask, int count) : m_flags(mask), m_restoreCount(count) { }
101 struct GraphicsContext::RecordingState {
102 RecordingState(SkCanvas* currentCanvas, const SkMatrix& currentMatrix, PassRefPtr<DisplayList> displayList)
103 : m_savedCanvas(currentCanvas)
104 , m_displayList(displayList)
105 , m_savedMatrix(currentMatrix)
109 SkCanvas* m_savedCanvas;
110 RefPtr<DisplayList> m_displayList;
111 const SkMatrix m_savedMatrix;
114 GraphicsContext::GraphicsContext(SkCanvas* canvas)
116 , m_paintStateStack()
117 , m_paintStateIndex(0)
118 , m_canvasSaveFlags(0)
119 , m_annotationMode(0)
121 , m_annotationCount(0)
124 , m_trackOpaqueRegion(false)
125 , m_trackTextRegion(false)
126 , m_useHighResMarker(false)
127 , m_updatingControlTints(false)
128 , m_accelerated(false)
129 , m_isCertainlyOpaque(true)
132 // FIXME: Do some tests to determine how many states are typically used, and allocate
134 m_paintStateStack.append(GraphicsContextState::create());
135 m_paintState = m_paintStateStack.last().get();
138 GraphicsContext::~GraphicsContext()
140 ASSERT(!m_paintStateIndex);
141 ASSERT(!m_paintState->m_saveCount);
142 ASSERT(!m_annotationCount);
143 ASSERT(!m_layerCount);
144 ASSERT(m_recordingStateStack.isEmpty());
147 const SkBitmap* GraphicsContext::bitmap() const
149 TRACE_EVENT0("skia", "GraphicsContext::bitmap");
150 return &m_canvas->getDevice()->accessBitmap(false);
153 const SkBitmap& GraphicsContext::layerBitmap(AccessMode access) const
155 return m_canvas->getTopDevice()->accessBitmap(access == ReadWrite);
158 void GraphicsContext::save()
160 if (paintingDisabled())
163 m_paintState->m_saveCount++;
165 m_canvasStateStack.append(CanvasSaveState(m_canvasSaveFlags, m_canvas->getSaveCount()));
166 m_canvasSaveFlags |= SkCanvas::kMatrixClip_SaveFlag;
169 void GraphicsContext::restore()
171 if (paintingDisabled())
174 if (!m_paintStateIndex && !m_paintState->m_saveCount) {
175 WTF_LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
179 if (m_paintState->m_saveCount) {
180 m_paintState->m_saveCount--;
183 m_paintState = m_paintStateStack[m_paintStateIndex].get();
186 CanvasSaveState savedState = m_canvasStateStack.last();
187 m_canvasStateStack.removeLast();
188 m_canvasSaveFlags = savedState.m_flags;
189 m_canvas->restoreToCount(savedState.m_restoreCount);
192 void GraphicsContext::saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags saveFlags)
194 if (paintingDisabled())
197 realizeCanvasSave(SkCanvas::kMatrixClip_SaveFlag);
199 m_canvas->saveLayer(bounds, paint, saveFlags);
201 m_canvas->clipRect(*bounds);
202 if (m_trackOpaqueRegion)
203 m_opaqueRegion.pushCanvasLayer(paint);
206 void GraphicsContext::restoreLayer()
208 if (paintingDisabled())
212 if (m_trackOpaqueRegion)
213 m_opaqueRegion.popCanvasLayer(this);
216 void GraphicsContext::beginAnnotation(const char* rendererName, const char* paintPhase,
217 const String& elementId, const String& elementClass, const String& elementTag)
219 if (paintingDisabled())
222 canvas()->beginCommentGroup("GraphicsContextAnnotation");
224 GraphicsContextAnnotation annotation(rendererName, paintPhase, elementId, elementClass, elementTag);
225 AnnotationList annotations;
226 annotation.asAnnotationList(annotations);
228 AnnotationList::const_iterator end = annotations.end();
229 for (AnnotationList::const_iterator it = annotations.begin(); it != end; ++it)
230 canvas()->addComment(it->first, it->second.ascii().data());
237 void GraphicsContext::endAnnotation()
239 if (paintingDisabled())
242 canvas()->endCommentGroup();
244 ASSERT(m_annotationCount > 0);
250 void GraphicsContext::setStrokeColor(const Color& color)
252 GraphicsContextState* stateToSet = mutableState();
253 stateToSet->m_strokeData.setColor(color);
254 stateToSet->m_strokeData.clearGradient();
255 stateToSet->m_strokeData.clearPattern();
258 void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
260 if (paintingDisabled())
265 setStrokeColor(Color::black);
268 GraphicsContextState* stateToSet = mutableState();
269 stateToSet->m_strokeData.clearGradient();
270 stateToSet->m_strokeData.setPattern(pattern);
273 void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
275 if (paintingDisabled())
280 setStrokeColor(Color::black);
283 GraphicsContextState* stateToSet = mutableState();
284 stateToSet->m_strokeData.setGradient(gradient);
285 stateToSet->m_strokeData.clearPattern();
288 void GraphicsContext::setFillColor(const Color& color)
290 GraphicsContextState* stateToSet = mutableState();
291 stateToSet->m_fillColor = color;
292 stateToSet->m_fillGradient.clear();
293 stateToSet->m_fillPattern.clear();
296 void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
298 if (paintingDisabled())
303 setFillColor(Color::black);
307 GraphicsContextState* stateToSet = mutableState();
308 stateToSet->m_fillGradient.clear();
309 stateToSet->m_fillPattern = pattern;
312 void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
314 if (paintingDisabled())
319 setFillColor(Color::black);
323 GraphicsContextState* stateToSet = mutableState();
324 stateToSet->m_fillGradient = gradient;
325 stateToSet->m_fillPattern.clear();
328 void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color& color,
329 DrawLooper::ShadowTransformMode shadowTransformMode,
330 DrawLooper::ShadowAlphaMode shadowAlphaMode)
332 if (paintingDisabled())
335 if (!color.alpha() || (!offset.width() && !offset.height() && !blur)) {
340 DrawLooper drawLooper;
341 drawLooper.addShadow(offset, blur, color, shadowTransformMode, shadowAlphaMode);
342 drawLooper.addUnmodifiedContent();
343 setDrawLooper(drawLooper);
346 void GraphicsContext::setDrawLooper(const DrawLooper& drawLooper)
348 if (paintingDisabled())
351 mutableState()->m_looper = drawLooper.skDrawLooper();
354 void GraphicsContext::clearDrawLooper()
356 if (paintingDisabled())
359 mutableState()->m_looper.clear();
362 bool GraphicsContext::hasShadow() const
364 return !!immutableState()->m_looper;
367 int GraphicsContext::getNormalizedAlpha() const
369 int alpha = roundf(immutableState()->m_alpha * 256);
377 FloatRect GraphicsContext::getClipBounds() const
379 if (paintingDisabled())
382 if (!m_canvas->getClipBounds(&rect))
384 return FloatRect(rect);
387 bool GraphicsContext::getTransformedClipBounds(FloatRect* bounds) const
389 if (paintingDisabled())
392 if (!m_canvas->getClipDeviceBounds(&skIBounds))
394 SkRect skBounds = SkRect::MakeFromIRect(skIBounds);
395 *bounds = FloatRect(skBounds);
399 SkMatrix GraphicsContext::getTotalMatrix() const
401 if (paintingDisabled())
402 return SkMatrix::I();
405 return m_canvas->getTotalMatrix();
407 const RecordingState& recordingState = m_recordingStateStack.last();
408 SkMatrix totalMatrix = recordingState.m_savedMatrix;
409 totalMatrix.preConcat(m_canvas->getTotalMatrix());
414 bool GraphicsContext::isPrintingDevice() const
416 if (paintingDisabled())
418 return m_canvas->getTopDevice()->getDeviceCapabilities() & SkBaseDevice::kVector_Capability;
421 void GraphicsContext::adjustTextRenderMode(SkPaint* paint)
423 if (paintingDisabled())
426 if (!paint->isLCDRenderText())
429 paint->setLCDRenderText(couldUseLCDRenderedText());
432 bool GraphicsContext::couldUseLCDRenderedText()
434 // Our layers only have a single alpha channel. This means that subpixel
435 // rendered text cannot be composited correctly when the layer is
436 // collapsed. Therefore, subpixel text is disabled when we are drawing
438 if (paintingDisabled() || isDrawingToLayer() || !isCertainlyOpaque())
441 return shouldSmoothFonts();
444 void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation, WebBlendMode blendMode)
446 GraphicsContextState* stateToSet = mutableState();
447 stateToSet->m_compositeOperator = compositeOperation;
448 stateToSet->m_blendMode = blendMode;
449 stateToSet->m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode);
452 SkColorFilter* GraphicsContext::colorFilter()
454 return immutableState()->m_colorFilter.get();
457 void GraphicsContext::setColorFilter(ColorFilter colorFilter)
459 GraphicsContextState* stateToSet = mutableState();
461 // We only support one active color filter at the moment. If (when) this becomes a problem,
462 // we should switch to using color filter chains (Skia work in progress).
463 ASSERT(!stateToSet->m_colorFilter);
464 stateToSet->m_colorFilter = WebCoreColorFilterToSkiaColorFilter(colorFilter);
467 bool GraphicsContext::readPixels(SkBitmap* bitmap, int x, int y, SkCanvas::Config8888 config8888)
469 if (paintingDisabled())
472 return m_canvas->readPixels(bitmap, x, y, config8888);
475 void GraphicsContext::setMatrix(const SkMatrix& matrix)
477 if (paintingDisabled())
480 realizeCanvasSave(SkCanvas::kMatrix_SaveFlag);
482 m_canvas->setMatrix(matrix);
485 bool GraphicsContext::concat(const SkMatrix& matrix)
487 if (paintingDisabled())
491 if (matrix.isIdentity())
494 realizeCanvasSave(SkCanvas::kMatrix_SaveFlag);
496 return m_canvas->concat(matrix);
499 void GraphicsContext::beginTransparencyLayer(float opacity, const FloatRect* bounds)
501 beginLayer(opacity, immutableState()->m_compositeOperator, bounds);
504 void GraphicsContext::beginLayer(float opacity, CompositeOperator op, const FloatRect* bounds, ColorFilter colorFilter, ImageFilter* imageFilter)
506 if (paintingDisabled())
509 // We need the "alpha" layer flag here because the base layer is opaque
510 // (the surface of the page) but layers on top may have transparent parts.
511 // Without explicitly setting the alpha flag, the layer will inherit the
512 // opaque setting of the base and some things won't work properly.
513 SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
516 layerPaint.setAlpha(static_cast<unsigned char>(opacity * 255));
517 layerPaint.setXfermode(WebCoreCompositeToSkiaComposite(op, m_paintState->m_blendMode).get());
518 layerPaint.setColorFilter(WebCoreColorFilterToSkiaColorFilter(colorFilter).get());
519 layerPaint.setImageFilter(imageFilter);
522 SkRect skBounds = WebCoreFloatRectToSKRect(*bounds);
523 saveLayer(&skBounds, &layerPaint, saveFlags);
525 saveLayer(0, &layerPaint, saveFlags);
533 void GraphicsContext::endLayer()
535 if (paintingDisabled())
540 ASSERT(m_layerCount > 0);
546 void GraphicsContext::beginRecording(const FloatRect& bounds)
548 RefPtr<DisplayList> displayList = adoptRef(new DisplayList(bounds));
550 SkCanvas* savedCanvas = m_canvas;
551 SkMatrix savedMatrix = getTotalMatrix();
553 IntRect recordingRect = enclosingIntRect(bounds);
554 m_canvas = displayList->picture()->beginRecording(recordingRect.width(), recordingRect.height(),
555 SkPicture::kUsePathBoundsForClip_RecordingFlag);
557 // We want the bounds offset mapped to (0, 0), such that the display list content
558 // is fully contained within the SkPictureRecord's bounds.
559 if (!toFloatSize(bounds.location()).isZero()) {
560 m_canvas->translate(-bounds.x(), -bounds.y());
561 // To avoid applying the offset repeatedly in getTotalMatrix(), we pre-apply it here.
562 savedMatrix.preTranslate(bounds.x(), bounds.y());
565 m_recordingStateStack.append(RecordingState(savedCanvas, savedMatrix, displayList));
568 PassRefPtr<DisplayList> GraphicsContext::endRecording()
570 ASSERT(!m_recordingStateStack.isEmpty());
572 RecordingState recording = m_recordingStateStack.last();
573 ASSERT(recording.m_displayList->picture()->getRecordingCanvas());
574 recording.m_displayList->picture()->endRecording();
576 m_recordingStateStack.removeLast();
577 m_canvas = recording.m_savedCanvas;
579 return recording.m_displayList.release();
582 bool GraphicsContext::isRecording() const
584 return !m_recordingStateStack.isEmpty();
587 void GraphicsContext::drawDisplayList(DisplayList* displayList)
590 ASSERT(!displayList->picture()->getRecordingCanvas());
592 if (paintingDisabled() || displayList->bounds().isEmpty())
595 realizeCanvasSave(SkCanvas::kMatrixClip_SaveFlag);
597 const FloatRect& bounds = displayList->bounds();
598 if (bounds.x() || bounds.y())
599 m_canvas->translate(bounds.x(), bounds.y());
601 m_canvas->drawPicture(*displayList->picture());
603 if (bounds.x() || bounds.y())
604 m_canvas->translate(-bounds.x(), -bounds.y());
607 void GraphicsContext::setupPaintForFilling(SkPaint* paint) const
609 if (paintingDisabled())
612 setupPaintCommon(paint);
614 setupShader(paint, immutableState()->m_fillGradient.get(), immutableState()->m_fillPattern.get(), immutableState()->m_fillColor.rgb());
617 float GraphicsContext::setupPaintForStroking(SkPaint* paint, int length) const
619 if (paintingDisabled())
622 setupPaintCommon(paint);
624 setupShader(paint, immutableState()->m_strokeData.gradient(), immutableState()->m_strokeData.pattern(),
625 immutableState()->m_strokeData.color().rgb());
627 return immutableState()->m_strokeData.setupPaint(paint, length);
630 void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
632 if (paintingDisabled())
639 setPathFromConvexPoints(&path, numPoints, points);
642 setupPaintForFilling(&paint);
643 paint.setAntiAlias(shouldAntialias);
644 drawPath(path, paint);
646 if (strokeStyle() != NoStroke) {
648 setupPaintForStroking(&paint);
649 drawPath(path, paint);
653 // This method is only used to draw the little circles used in lists.
654 void GraphicsContext::drawEllipse(const IntRect& elipseRect)
656 if (paintingDisabled())
659 SkRect rect = elipseRect;
661 setupPaintForFilling(&paint);
662 drawOval(rect, paint);
664 if (strokeStyle() != NoStroke) {
666 setupPaintForStroking(&paint);
667 drawOval(rect, paint);
671 void GraphicsContext::drawFocusRing(const Path& focusRingPath, int width, int offset, const Color& color)
673 // FIXME: Implement support for offset.
674 if (paintingDisabled())
678 paint.setAntiAlias(true);
679 paint.setStyle(SkPaint::kStroke_Style);
680 paint.setColor(color.rgb());
682 drawOuterPath(focusRingPath.skPath(), paint, width);
683 drawInnerPath(focusRingPath.skPath(), paint, width);
686 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
688 if (paintingDisabled())
691 unsigned rectCount = rects.size();
695 SkRegion focusRingRegion;
696 const int focusRingOutset = getFocusRingOutset(offset);
697 for (unsigned i = 0; i < rectCount; i++) {
698 SkIRect r = rects[i];
699 r.inset(-focusRingOutset, -focusRingOutset);
700 focusRingRegion.op(r, SkRegion::kUnion_Op);
705 paint.setAntiAlias(true);
706 paint.setStyle(SkPaint::kStroke_Style);
708 paint.setColor(color.rgb());
709 focusRingRegion.getBoundaryPath(&path);
710 drawOuterPath(path, paint, width);
711 drawInnerPath(path, paint, width);
714 static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset)
716 IntRect bounds(holeRect);
718 bounds.inflate(shadowBlur);
720 if (shadowSpread < 0)
721 bounds.inflate(-shadowSpread);
723 IntRect offsetBounds = bounds;
724 offsetBounds.move(-shadowOffset);
725 return unionRect(bounds, offsetBounds);
728 void GraphicsContext::drawInnerShadow(const RoundedRect& rect, const Color& shadowColor, const IntSize shadowOffset, int shadowBlur, int shadowSpread, Edges clippedEdges)
730 IntRect holeRect(rect.rect());
731 holeRect.inflate(-shadowSpread);
733 if (holeRect.isEmpty()) {
734 if (rect.isRounded())
735 fillRoundedRect(rect, shadowColor);
737 fillRect(rect.rect(), shadowColor);
741 if (clippedEdges & LeftEdge) {
742 holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0);
743 holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur);
745 if (clippedEdges & TopEdge) {
746 holeRect.move(0, -max(shadowOffset.height(), 0) - shadowBlur);
747 holeRect.setHeight(holeRect.height() + max(shadowOffset.height(), 0) + shadowBlur);
749 if (clippedEdges & RightEdge)
750 holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur);
751 if (clippedEdges & BottomEdge)
752 holeRect.setHeight(holeRect.height() - min(shadowOffset.height(), 0) + shadowBlur);
754 Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255);
756 IntRect outerRect = areaCastingShadowInHole(rect.rect(), shadowBlur, shadowSpread, shadowOffset);
757 RoundedRect roundedHole(holeRect, rect.radii());
760 if (rect.isRounded()) {
762 path.addRoundedRect(rect);
764 roundedHole.shrinkRadii(shadowSpread);
769 DrawLooper drawLooper;
770 drawLooper.addShadow(shadowOffset, shadowBlur, shadowColor,
771 DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha);
772 setDrawLooper(drawLooper);
773 fillRectWithRoundedHole(outerRect, roundedHole, fillColor);
778 // This is only used to draw borders.
779 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
781 if (paintingDisabled())
784 StrokeStyle penStyle = strokeStyle();
785 if (penStyle == NoStroke)
789 FloatPoint p1 = point1;
790 FloatPoint p2 = point2;
791 bool isVerticalLine = (p1.x() == p2.x());
792 int width = roundf(strokeThickness());
794 // We know these are vertical or horizontal lines, so the length will just
795 // be the sum of the displacement component vectors give or take 1 -
796 // probably worth the speed up of no square root, which also won't be exact.
797 FloatSize disp = p2 - p1;
798 int length = SkScalarRoundToInt(disp.width() + disp.height());
799 setupPaintForStroking(&paint, length);
801 if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
802 // Do a rect fill of our endpoints. This ensures we always have the
803 // appearance of being a border. We then draw the actual dotted/dashed line.
806 r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
807 r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
809 if (isVerticalLine) {
810 r1.offset(-width / 2, 0);
811 r2.offset(-width / 2, -width);
813 r1.offset(0, -width / 2);
814 r2.offset(-width, -width / 2);
817 fillPaint.setColor(paint.getColor());
818 drawRect(r1, fillPaint);
819 drawRect(r2, fillPaint);
822 adjustLineToPixelBoundaries(p1, p2, width, penStyle);
823 SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
825 m_canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
827 if (m_trackOpaqueRegion)
828 m_opaqueRegion.didDrawPoints(this, SkCanvas::kLines_PointMode, 2, pts, paint);
831 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float width, DocumentMarkerLineStyle style)
833 if (paintingDisabled())
836 int deviceScaleFactor = m_useHighResMarker ? 2 : 1;
838 // Create the pattern we'll use to draw the underline.
839 int index = style == DocumentMarkerGrammarLineStyle ? 1 : 0;
840 static SkBitmap* misspellBitmap1x[2] = { 0, 0 };
841 static SkBitmap* misspellBitmap2x[2] = { 0, 0 };
842 SkBitmap** misspellBitmap = deviceScaleFactor == 2 ? misspellBitmap2x : misspellBitmap1x;
843 if (!misspellBitmap[index]) {
845 // Match the artwork used by the Mac.
846 const int rowPixels = 4 * deviceScaleFactor;
847 const int colPixels = 3 * deviceScaleFactor;
848 misspellBitmap[index] = new SkBitmap;
849 misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config,
850 rowPixels, colPixels);
851 misspellBitmap[index]->allocPixels();
853 misspellBitmap[index]->eraseARGB(0, 0, 0, 0);
854 const uint32_t transparentColor = 0x00000000;
856 if (deviceScaleFactor == 1) {
857 const uint32_t colors[2][6] = {
858 { 0x2a2a0600, 0x57571000, 0xa8a81b00, 0xbfbf1f00, 0x70701200, 0xe0e02400 },
859 { 0x2a0f0f0f, 0x571e1e1e, 0xa83d3d3d, 0xbf454545, 0x70282828, 0xe0515151 }
862 // Pattern: a b a a b a
865 for (int x = 0; x < colPixels; ++x) {
866 uint32_t* row = misspellBitmap[index]->getAddr32(0, x);
867 row[0] = colors[index][x * 2];
868 row[1] = colors[index][x * 2 + 1];
869 row[2] = colors[index][x * 2];
870 row[3] = transparentColor;
872 } else if (deviceScaleFactor == 2) {
873 const uint32_t colors[2][18] = {
874 { 0x0a090101, 0x33320806, 0x55540f0a, 0x37360906, 0x6e6c120c, 0x6e6c120c, 0x7674140d, 0x8d8b1810, 0x8d8b1810,
875 0x96941a11, 0xb3b01f15, 0xb3b01f15, 0x6d6b130c, 0xd9d62619, 0xd9d62619, 0x19180402, 0x7c7a150e, 0xcecb2418 },
876 { 0x0a020202, 0x33141414, 0x55232323, 0x37161616, 0x6e2e2e2e, 0x6e2e2e2e, 0x76313131, 0x8d3a3a3a, 0x8d3a3a3a,
877 0x963e3e3e, 0xb34b4b4b, 0xb34b4b4b, 0x6d2d2d2d, 0xd95b5b5b, 0xd95b5b5b, 0x19090909, 0x7c343434, 0xce575757 }
880 // Pattern: a b c c b a
886 for (int x = 0; x < colPixels; ++x) {
887 uint32_t* row = misspellBitmap[index]->getAddr32(0, x);
888 row[0] = colors[index][x * 3];
889 row[1] = colors[index][x * 3 + 1];
890 row[2] = colors[index][x * 3 + 2];
891 row[3] = colors[index][x * 3 + 2];
892 row[4] = colors[index][x * 3 + 1];
893 row[5] = colors[index][x * 3];
894 row[6] = transparentColor;
895 row[7] = transparentColor;
898 ASSERT_NOT_REACHED();
900 // We use a 2-pixel-high misspelling indicator because that seems to be
901 // what WebKit is designed for, and how much room there is in a typical
903 const int rowPixels = 32 * deviceScaleFactor; // Must be multiple of 4 for pattern below.
904 const int colPixels = 2 * deviceScaleFactor;
905 misspellBitmap[index] = new SkBitmap;
906 misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels);
907 misspellBitmap[index]->allocPixels();
909 misspellBitmap[index]->eraseARGB(0, 0, 0, 0);
910 if (deviceScaleFactor == 1)
911 draw1xMarker(misspellBitmap[index], index);
912 else if (deviceScaleFactor == 2)
913 draw2xMarker(misspellBitmap[index], index);
915 ASSERT_NOT_REACHED();
920 SkScalar originX = WebCoreFloatToSkScalar(pt.x()) * deviceScaleFactor;
921 SkScalar originY = WebCoreFloatToSkScalar(pt.y()) * deviceScaleFactor;
923 // Make sure to draw only complete dots.
924 int rowPixels = misspellBitmap[index]->width();
925 float widthMod = fmodf(width * deviceScaleFactor, rowPixels);
926 if (rowPixels - widthMod > deviceScaleFactor)
927 width -= widthMod / deviceScaleFactor;
929 SkScalar originX = WebCoreFloatToSkScalar(pt.x());
931 // Offset it vertically by 1 so that there's some space under the text.
932 SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
933 originX *= deviceScaleFactor;
934 originY *= deviceScaleFactor;
937 RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader(
938 *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
940 matrix.setTranslate(originX, originY);
941 shader->setLocalMatrix(matrix);
944 paint.setShader(shader.get());
947 rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width) * deviceScaleFactor, originY + SkIntToScalar(misspellBitmap[index]->height()));
949 if (deviceScaleFactor == 2) {
951 scale(FloatSize(0.5, 0.5));
953 drawRect(rect, paint);
954 if (deviceScaleFactor == 2)
958 void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool printing)
960 if (paintingDisabled())
966 int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
968 r.fLeft = WebCoreFloatToSkScalar(pt.x());
969 // Avoid anti-aliasing lines. Currently, these are always horizontal.
970 // Round to nearest pixel to match text and other content.
971 r.fTop = WebCoreFloatToSkScalar(floorf(pt.y() + 0.5f));
972 r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
973 r.fBottom = r.fTop + SkIntToScalar(thickness);
976 switch (strokeStyle()) {
981 setupPaintForFilling(&paint);
985 setupPaintForStroking(&paint);
989 // Text lines are drawn using the stroke color.
990 paint.setColor(effectiveStrokeColor());
994 // Draws a filled rectangle with a stroked border.
995 void GraphicsContext::drawRect(const IntRect& rect)
997 if (paintingDisabled())
1000 ASSERT(!rect.isEmpty());
1004 SkRect skRect = rect;
1006 int fillcolorNotTransparent = m_paintState->m_fillColor.rgb() & 0xFF000000;
1007 if (fillcolorNotTransparent) {
1008 setupPaintForFilling(&paint);
1009 drawRect(skRect, paint);
1012 if (m_paintState->m_strokeData.style() != NoStroke && (m_paintState->m_strokeData.color().rgb() & 0xFF000000)) {
1013 // We do a fill of four rects to simulate the stroke of a border.
1015 setupPaintForFilling(&paint);
1016 // need to jam in the strokeColor
1017 paint.setColor(this->effectiveStrokeColor());
1019 SkRect topBorder = { skRect.fLeft, skRect.fTop, skRect.fRight, skRect.fTop + 1 };
1020 drawRect(topBorder, paint);
1021 SkRect bottomBorder = { skRect.fLeft, skRect.fBottom - 1, skRect.fRight, skRect.fBottom };
1022 drawRect(bottomBorder, paint);
1023 SkRect leftBorder = { skRect.fLeft, skRect.fTop + 1, skRect.fLeft + 1, skRect.fBottom - 1 };
1024 drawRect(leftBorder, paint);
1025 SkRect rightBorder = { skRect.fRight - 1, skRect.fTop + 1, skRect.fRight, skRect.fBottom - 1 };
1026 drawRect(rightBorder, paint);
1030 void GraphicsContext::drawText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point)
1032 if (paintingDisabled())
1035 font.drawText(this, runInfo, point);
1038 void GraphicsContext::drawEmphasisMarks(const Font& font, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point)
1040 if (paintingDisabled())
1043 font.drawEmphasisMarks(this, runInfo, mark, point);
1046 void GraphicsContext::drawBidiText(const Font& font, const TextRunPaintInfo& runInfo, const FloatPoint& point, Font::CustomFontNotReadyAction customFontNotReadyAction)
1048 if (paintingDisabled())
1051 // sub-run painting is not supported for Bidi text.
1052 const TextRun& run = runInfo.run;
1053 ASSERT((runInfo.from == 0) && (runInfo.to == run.length()));
1054 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
1055 bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
1056 bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
1058 // FIXME: This ownership should be reversed. We should pass BidiRunList
1059 // to BidiResolver in createBidiRunsForLine.
1060 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
1061 bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
1062 if (!bidiRuns.runCount())
1065 FloatPoint currPoint = point;
1066 BidiCharacterRun* bidiRun = bidiRuns.firstRun();
1068 TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
1069 bool isRTL = bidiRun->level() % 2;
1070 subrun.setDirection(isRTL ? RTL : LTR);
1071 subrun.setDirectionalOverride(bidiRun->dirOverride(false));
1073 TextRunPaintInfo subrunInfo(subrun);
1074 subrunInfo.bounds = runInfo.bounds;
1075 font.drawText(this, subrunInfo, currPoint, customFontNotReadyAction);
1077 bidiRun = bidiRun->next();
1078 // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
1080 currPoint.move(font.width(subrun), 0);
1083 bidiRuns.deleteRuns();
1086 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, int from, int to)
1088 if (paintingDisabled())
1091 fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor);
1094 void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
1098 drawImage(image, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation);
1101 void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
1105 drawImage(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, shouldRespectImageOrientation, useLowQualityScale);
1108 void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation)
1110 drawImage(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, shouldRespectImageOrientation);
1113 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
1115 drawImage(image, dest, src, op, blink::WebBlendModeNormal, shouldRespectImageOrientation, useLowQualityScale);
1118 void GraphicsContext::drawImage(Image* image, const FloatRect& dest)
1122 drawImage(image, dest, FloatRect(IntRect(IntPoint(), image->size())));
1125 void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, WebBlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation, bool useLowQualityScale)
1126 { if (paintingDisabled() || !image)
1129 InterpolationQuality previousInterpolationQuality = InterpolationDefault;
1131 if (useLowQualityScale) {
1132 previousInterpolationQuality = imageInterpolationQuality();
1133 setImageInterpolationQuality(InterpolationLow);
1136 image->draw(this, dest, src, op, blendMode, shouldRespectImageOrientation);
1138 if (useLowQualityScale)
1139 setImageInterpolationQuality(previousInterpolationQuality);
1142 void GraphicsContext::drawTiledImage(Image* image, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale, WebBlendMode blendMode, const IntSize& repeatSpacing)
1144 if (paintingDisabled() || !image)
1147 if (useLowQualityScale) {
1148 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
1149 setImageInterpolationQuality(InterpolationLow);
1150 image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode, repeatSpacing);
1151 setImageInterpolationQuality(previousInterpolationQuality);
1153 image->drawTiled(this, destRect, srcPoint, tileSize, op, blendMode, repeatSpacing);
1157 void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect,
1158 const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
1160 if (paintingDisabled() || !image)
1163 if (hRule == Image::StretchTile && vRule == Image::StretchTile) {
1165 drawImage(image, dest, srcRect, op);
1169 if (useLowQualityScale) {
1170 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
1171 setImageInterpolationQuality(InterpolationLow);
1172 image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op);
1173 setImageInterpolationQuality(previousInterpolationQuality);
1175 image->drawTiled(this, dest, srcRect, tileScaleFactor, hRule, vRule, op);
1179 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& p, CompositeOperator op, WebBlendMode blendMode)
1183 drawImageBuffer(image, FloatRect(IntRect(p, image->size())), FloatRect(FloatPoint(), FloatSize(image->size())), op, blendMode);
1186 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& r, CompositeOperator op, WebBlendMode blendMode, bool useLowQualityScale)
1190 drawImageBuffer(image, FloatRect(r), FloatRect(FloatPoint(), FloatSize(image->size())), op, blendMode, useLowQualityScale);
1193 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op, WebBlendMode blendMode)
1195 drawImageBuffer(image, FloatRect(IntRect(dest, srcRect.size())), FloatRect(srcRect), op, blendMode);
1198 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, WebBlendMode blendMode, bool useLowQualityScale)
1200 drawImageBuffer(image, FloatRect(dest), FloatRect(srcRect), op, blendMode, useLowQualityScale);
1203 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest)
1207 drawImageBuffer(image, dest, FloatRect(IntRect(IntPoint(), image->size())));
1210 void GraphicsContext::drawImageBuffer(ImageBuffer* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, WebBlendMode blendMode, bool useLowQualityScale)
1212 if (paintingDisabled() || !image)
1215 if (useLowQualityScale) {
1216 InterpolationQuality previousInterpolationQuality = imageInterpolationQuality();
1217 setImageInterpolationQuality(InterpolationLow);
1218 image->draw(this, dest, src, op, blendMode, useLowQualityScale);
1219 setImageInterpolationQuality(previousInterpolationQuality);
1221 image->draw(this, dest, src, op, blendMode, useLowQualityScale);
1225 void GraphicsContext::writePixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888)
1227 if (paintingDisabled())
1230 m_canvas->writePixels(bitmap, x, y, config8888);
1232 if (m_trackOpaqueRegion) {
1233 SkRect rect = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1236 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1237 m_opaqueRegion.didDrawRect(this, rect, paint, &bitmap);
1241 void GraphicsContext::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint)
1243 if (paintingDisabled())
1246 m_canvas->drawBitmap(bitmap, left, top, paint);
1248 if (m_trackOpaqueRegion) {
1249 SkRect rect = SkRect::MakeXYWH(left, top, bitmap.width(), bitmap.height());
1250 m_opaqueRegion.didDrawRect(this, rect, *paint, &bitmap);
1254 void GraphicsContext::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
1255 const SkRect& dst, const SkPaint* paint)
1257 if (paintingDisabled())
1260 SkCanvas::DrawBitmapRectFlags flags = m_paintState->m_shouldClampToSourceRect ? SkCanvas::kNone_DrawBitmapRectFlag : SkCanvas::kBleed_DrawBitmapRectFlag;
1262 m_canvas->drawBitmapRectToRect(bitmap, src, dst, paint, flags);
1264 if (m_trackOpaqueRegion)
1265 m_opaqueRegion.didDrawRect(this, dst, *paint, &bitmap);
1268 void GraphicsContext::drawOval(const SkRect& oval, const SkPaint& paint)
1270 if (paintingDisabled())
1273 m_canvas->drawOval(oval, paint);
1275 if (m_trackOpaqueRegion)
1276 m_opaqueRegion.didDrawBounded(this, oval, paint);
1279 void GraphicsContext::drawPath(const SkPath& path, const SkPaint& paint)
1281 if (paintingDisabled())
1284 m_canvas->drawPath(path, paint);
1286 if (m_trackOpaqueRegion)
1287 m_opaqueRegion.didDrawPath(this, path, paint);
1290 void GraphicsContext::drawRect(const SkRect& rect, const SkPaint& paint)
1292 if (paintingDisabled())
1295 m_canvas->drawRect(rect, paint);
1297 if (m_trackOpaqueRegion)
1298 m_opaqueRegion.didDrawRect(this, rect, paint, 0);
1301 void GraphicsContext::didDrawRect(const SkRect& rect, const SkPaint& paint, const SkBitmap* bitmap)
1303 if (m_trackOpaqueRegion)
1304 m_opaqueRegion.didDrawRect(this, rect, paint, bitmap);
1307 void GraphicsContext::drawPosText(const void* text, size_t byteLength,
1308 const SkPoint pos[], const SkRect& textRect, const SkPaint& paint)
1310 if (paintingDisabled())
1313 m_canvas->drawPosText(text, byteLength, pos, paint);
1314 didDrawTextInRect(textRect);
1316 // FIXME: compute bounds for positioned text.
1317 if (m_trackOpaqueRegion)
1318 m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke);
1321 void GraphicsContext::drawPosTextH(const void* text, size_t byteLength,
1322 const SkScalar xpos[], SkScalar constY, const SkRect& textRect, const SkPaint& paint)
1324 if (paintingDisabled())
1327 m_canvas->drawPosTextH(text, byteLength, xpos, constY, paint);
1328 didDrawTextInRect(textRect);
1330 // FIXME: compute bounds for positioned text.
1331 if (m_trackOpaqueRegion)
1332 m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke);
1335 void GraphicsContext::drawTextOnPath(const void* text, size_t byteLength,
1336 const SkPath& path, const SkRect& textRect, const SkMatrix* matrix, const SkPaint& paint)
1338 if (paintingDisabled())
1341 m_canvas->drawTextOnPath(text, byteLength, path, matrix, paint);
1342 didDrawTextInRect(textRect);
1344 // FIXME: compute bounds for positioned text.
1345 if (m_trackOpaqueRegion)
1346 m_opaqueRegion.didDrawUnbounded(this, paint, OpaqueRegionSkia::FillOrStroke);
1349 void GraphicsContext::fillPath(const Path& pathToFill)
1351 if (paintingDisabled() || pathToFill.isEmpty())
1354 // Use const_cast and temporarily modify the fill type instead of copying the path.
1355 SkPath& path = const_cast<SkPath&>(pathToFill.skPath());
1356 SkPath::FillType previousFillType = path.getFillType();
1358 SkPath::FillType temporaryFillType = m_paintState->m_fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
1359 path.setFillType(temporaryFillType);
1362 setupPaintForFilling(&paint);
1363 drawPath(path, paint);
1365 path.setFillType(previousFillType);
1368 void GraphicsContext::fillRect(const FloatRect& rect)
1370 if (paintingDisabled())
1376 setupPaintForFilling(&paint);
1380 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
1382 if (paintingDisabled())
1387 setupPaintCommon(&paint);
1388 paint.setColor(color.rgb());
1392 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
1393 const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
1395 if (paintingDisabled())
1398 if (topLeft.width() + topRight.width() > rect.width()
1399 || bottomLeft.width() + bottomRight.width() > rect.width()
1400 || topLeft.height() + bottomLeft.height() > rect.height()
1401 || topRight.height() + bottomRight.height() > rect.height()) {
1402 // Not all the radii fit, return a rect. This matches the behavior of
1403 // Path::createRoundedRectangle. Without this we attempt to draw a round
1404 // shadow for a square box.
1405 fillRect(rect, color);
1410 setRadii(radii, topLeft, topRight, bottomRight, bottomLeft);
1413 rr.setRectRadii(rect, radii);
1416 setupPaintForFilling(&paint);
1417 paint.setColor(color.rgb());
1419 m_canvas->drawRRect(rr, paint);
1421 if (m_trackOpaqueRegion)
1422 m_opaqueRegion.didDrawBounded(this, rr.getBounds(), paint);
1425 void GraphicsContext::fillEllipse(const FloatRect& ellipse)
1427 if (paintingDisabled())
1430 SkRect rect = ellipse;
1432 setupPaintForFilling(&paint);
1433 drawOval(rect, paint);
1436 void GraphicsContext::strokePath(const Path& pathToStroke)
1438 if (paintingDisabled() || pathToStroke.isEmpty())
1441 const SkPath& path = pathToStroke.skPath();
1443 setupPaintForStroking(&paint);
1444 drawPath(path, paint);
1447 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
1449 if (paintingDisabled())
1453 setupPaintForStroking(&paint);
1454 paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
1455 // strokerect has special rules for CSS when the rect is degenerate:
1456 // if width==0 && height==0, do nothing
1457 // if width==0 || height==0, then just draw line for the other dimension
1459 bool validW = r.width() > 0;
1460 bool validH = r.height() > 0;
1461 if (validW && validH) {
1463 } else if (validW || validH) {
1464 // we are expected to respect the lineJoin, so we can't just call
1465 // drawLine -- we have to create a path that doubles back on itself.
1467 path.moveTo(r.fLeft, r.fTop);
1468 path.lineTo(r.fRight, r.fBottom);
1470 drawPath(path, paint);
1474 void GraphicsContext::strokeEllipse(const FloatRect& ellipse)
1476 if (paintingDisabled())
1479 SkRect rect(ellipse);
1481 setupPaintForStroking(&paint);
1482 drawOval(rect, paint);
1485 void GraphicsContext::clipRoundedRect(const RoundedRect& rect)
1487 if (paintingDisabled())
1491 RoundedRect::Radii wkRadii = rect.radii();
1492 setRadii(radii, wkRadii.topLeft(), wkRadii.topRight(), wkRadii.bottomRight(), wkRadii.bottomLeft());
1495 r.setRectRadii(rect.rect(), radii);
1497 clipRRect(r, AntiAliased);
1500 void GraphicsContext::clipOut(const Path& pathToClip)
1502 if (paintingDisabled())
1505 // Use const_cast and temporarily toggle the inverse fill type instead of copying the path.
1506 SkPath& path = const_cast<SkPath&>(pathToClip.skPath());
1507 path.toggleInverseFillType();
1508 clipPath(path, AntiAliased);
1509 path.toggleInverseFillType();
1512 void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
1514 if (paintingDisabled() || pathToClip.isEmpty())
1517 // Use const_cast and temporarily modify the fill type instead of copying the path.
1518 SkPath& path = const_cast<SkPath&>(pathToClip.skPath());
1519 SkPath::FillType previousFillType = path.getFillType();
1521 SkPath::FillType temporaryFillType = clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
1522 path.setFillType(temporaryFillType);
1523 clipPath(path, AntiAliased);
1525 path.setFillType(previousFillType);
1528 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
1530 if (paintingDisabled())
1537 setPathFromConvexPoints(&path, numPoints, points);
1538 clipPath(path, antialiased ? AntiAliased : NotAntiAliased);
1541 void GraphicsContext::clipOutRoundedRect(const RoundedRect& rect)
1543 if (paintingDisabled())
1546 if (!rect.isRounded()) {
1547 clipOut(rect.rect());
1552 path.addRoundedRect(rect);
1556 void GraphicsContext::canvasClip(const Path& pathToClip, WindRule clipRule)
1558 if (paintingDisabled())
1561 // Use const_cast and temporarily modify the fill type instead of copying the path.
1562 SkPath& path = const_cast<SkPath&>(pathToClip.skPath());
1563 SkPath::FillType previousFillType = path.getFillType();
1565 SkPath::FillType temporaryFillType = clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
1566 path.setFillType(temporaryFillType);
1569 path.setFillType(previousFillType);
1572 bool GraphicsContext::clipRect(const SkRect& rect, AntiAliasingMode aa, SkRegion::Op op)
1574 if (paintingDisabled())
1577 realizeCanvasSave(SkCanvas::kClip_SaveFlag);
1579 return m_canvas->clipRect(rect, op, aa == AntiAliased);
1582 bool GraphicsContext::clipPath(const SkPath& path, AntiAliasingMode aa, SkRegion::Op op)
1584 if (paintingDisabled())
1587 realizeCanvasSave(SkCanvas::kClip_SaveFlag);
1589 return m_canvas->clipPath(path, op, aa == AntiAliased);
1592 bool GraphicsContext::clipRRect(const SkRRect& rect, AntiAliasingMode aa, SkRegion::Op op)
1594 if (paintingDisabled())
1597 realizeCanvasSave(SkCanvas::kClip_SaveFlag);
1599 return m_canvas->clipRRect(rect, op, aa == AntiAliased);
1602 void GraphicsContext::rotate(float angleInRadians)
1604 if (paintingDisabled())
1607 realizeCanvasSave(SkCanvas::kMatrix_SaveFlag);
1609 m_canvas->rotate(WebCoreFloatToSkScalar(angleInRadians * (180.0f / 3.14159265f)));
1612 void GraphicsContext::translate(float w, float h)
1614 if (paintingDisabled())
1620 realizeCanvasSave(SkCanvas::kMatrix_SaveFlag);
1622 m_canvas->translate(WebCoreFloatToSkScalar(w), WebCoreFloatToSkScalar(h));
1625 void GraphicsContext::scale(const FloatSize& size)
1627 if (paintingDisabled())
1630 if (size.width() == 1.0f && size.height() == 1.0f)
1633 realizeCanvasSave(SkCanvas::kMatrix_SaveFlag);
1635 m_canvas->scale(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height()));
1638 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
1640 if (paintingDisabled())
1643 SkAutoDataUnref url(SkData::NewWithCString(link.string().utf8().data()));
1644 SkAnnotateRectWithURL(m_canvas, destRect, url.get());
1647 void GraphicsContext::setURLFragmentForRect(const String& destName, const IntRect& rect)
1649 if (paintingDisabled())
1652 SkAutoDataUnref skDestName(SkData::NewWithCString(destName.utf8().data()));
1653 SkAnnotateLinkToDestination(m_canvas, rect, skDestName.get());
1656 void GraphicsContext::addURLTargetAtPoint(const String& name, const IntPoint& pos)
1658 if (paintingDisabled())
1661 SkAutoDataUnref nameData(SkData::NewWithCString(name.utf8().data()));
1662 SkAnnotateNamedDestination(m_canvas, SkPoint::Make(pos.x(), pos.y()), nameData);
1665 AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
1667 if (paintingDisabled())
1668 return AffineTransform();
1670 SkMatrix m = getTotalMatrix();
1671 return AffineTransform(SkScalarToDouble(m.getScaleX()),
1672 SkScalarToDouble(m.getSkewY()),
1673 SkScalarToDouble(m.getSkewX()),
1674 SkScalarToDouble(m.getScaleY()),
1675 SkScalarToDouble(m.getTranslateX()),
1676 SkScalarToDouble(m.getTranslateY()));
1679 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, CompositeOperator op)
1681 if (paintingDisabled())
1684 CompositeOperator previousOperator = compositeOperation();
1685 setCompositeOperation(op);
1686 fillRect(rect, color);
1687 setCompositeOperation(previousOperator);
1690 void GraphicsContext::fillRoundedRect(const RoundedRect& rect, const Color& color)
1692 if (rect.isRounded())
1693 fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color);
1695 fillRect(rect.rect(), color);
1698 void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedRect& roundedHoleRect, const Color& color)
1700 if (paintingDisabled())
1706 if (!roundedHoleRect.radii().isZero())
1707 path.addRoundedRect(roundedHoleRect);
1709 path.addRect(roundedHoleRect.rect());
1711 WindRule oldFillRule = fillRule();
1712 Color oldFillColor = fillColor();
1714 setFillRule(RULE_EVENODD);
1715 setFillColor(color);
1719 setFillRule(oldFillRule);
1720 setFillColor(oldFillColor);
1723 void GraphicsContext::clearRect(const FloatRect& rect)
1725 if (paintingDisabled())
1730 setupPaintForFilling(&paint);
1731 paint.setXfermodeMode(SkXfermode::kClear_Mode);
1735 void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
1737 // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
1738 // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
1739 // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave
1740 // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
1741 if (penStyle == DottedStroke || penStyle == DashedStroke) {
1742 if (p1.x() == p2.x()) {
1743 p1.setY(p1.y() + strokeWidth);
1744 p2.setY(p2.y() - strokeWidth);
1746 p1.setX(p1.x() + strokeWidth);
1747 p2.setX(p2.x() - strokeWidth);
1751 if (static_cast<int>(strokeWidth) % 2) { //odd
1752 if (p1.x() == p2.x()) {
1753 // We're a vertical line. Adjust our x.
1754 p1.setX(p1.x() + 0.5f);
1755 p2.setX(p2.x() + 0.5f);
1757 // We're a horizontal line. Adjust our y.
1758 p1.setY(p1.y() + 0.5f);
1759 p2.setY(p2.y() + 0.5f);
1764 PassOwnPtr<ImageBuffer> GraphicsContext::createCompatibleBuffer(const IntSize& size, OpacityMode opacityMode) const
1766 // Make the buffer larger if the context's transform is scaling it so we need a higher
1767 // resolution than one pixel per unit. Also set up a corresponding scale factor on the
1768 // graphics context.
1770 AffineTransform transform = getCTM(DefinitelyIncludeDeviceScale);
1771 IntSize scaledSize(static_cast<int>(ceil(size.width() * transform.xScale())), static_cast<int>(ceil(size.height() * transform.yScale())));
1773 RefPtr<SkBaseDevice> device = adoptRef(m_canvas->getTopDevice()->createCompatibleDevice(SkBitmap::kARGB_8888_Config, size.width(), size.height(), opacityMode == Opaque));
1776 OwnPtr<ImageBufferSurface> surface = adoptPtr(new CompatibleImageBufferSurface(device.release(), scaledSize, opacityMode));
1777 ASSERT(surface->isValid());
1778 OwnPtr<ImageBuffer> buffer = adoptPtr(new ImageBuffer(surface.release()));
1780 buffer->context()->scale(FloatSize(static_cast<float>(scaledSize.width()) / size.width(),
1781 static_cast<float>(scaledSize.height()) / size.height()));
1783 return buffer.release();
1786 void GraphicsContext::addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
1789 int rx = SkMin32(SkScalarRoundToInt(rect.width()), size.width());
1790 int ry = SkMin32(SkScalarRoundToInt(rect.height()), size.height());
1792 ir.set(-rx, -ry, rx, ry);
1793 switch (startAngle) {
1795 ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
1798 ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
1801 ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
1804 ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
1812 path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
1815 void GraphicsContext::setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points)
1817 path->incReserve(numPoints);
1818 path->moveTo(WebCoreFloatToSkScalar(points[0].x()),
1819 WebCoreFloatToSkScalar(points[0].y()));
1820 for (size_t i = 1; i < numPoints; ++i) {
1821 path->lineTo(WebCoreFloatToSkScalar(points[i].x()),
1822 WebCoreFloatToSkScalar(points[i].y()));
1825 /* The code used to just blindly call this
1826 path->setIsConvex(true);
1827 But webkit can sometimes send us non-convex 4-point values, so we mark the path's
1828 convexity as unknown, so it will get computed by skia at draw time.
1829 See crbug.com 108605
1831 SkPath::Convexity convexity = SkPath::kConvex_Convexity;
1833 convexity = SkPath::kUnknown_Convexity;
1834 path->setConvexity(convexity);
1837 void GraphicsContext::setupPaintCommon(SkPaint* paint) const
1839 #if defined(SK_DEBUG)
1841 SkPaint defaultPaint;
1842 SkASSERT(*paint == defaultPaint);
1846 paint->setAntiAlias(m_paintState->m_shouldAntialias);
1848 if (!SkXfermode::IsMode(m_paintState->m_xferMode.get(), SkXfermode::kSrcOver_Mode))
1849 paint->setXfermode(m_paintState->m_xferMode.get());
1851 if (m_paintState->m_looper)
1852 paint->setLooper(m_paintState->m_looper.get());
1854 paint->setColorFilter(m_paintState->m_colorFilter.get());
1857 void GraphicsContext::drawOuterPath(const SkPath& path, SkPaint& paint, int width)
1861 paint.setStrokeWidth(width);
1862 paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref();
1864 paint.setStrokeWidth(1);
1865 paint.setPathEffect(new SkCornerPathEffect(1))->unref();
1867 drawPath(path, paint);
1870 void GraphicsContext::drawInnerPath(const SkPath& path, SkPaint& paint, int width)
1873 paint.setAlpha(128);
1874 paint.setStrokeWidth(width * 0.5f);
1875 drawPath(path, paint);
1879 void GraphicsContext::setRadii(SkVector* radii, IntSize topLeft, IntSize topRight, IntSize bottomRight, IntSize bottomLeft)
1881 radii[SkRRect::kUpperLeft_Corner].set(SkIntToScalar(topLeft.width()),
1882 SkIntToScalar(topLeft.height()));
1883 radii[SkRRect::kUpperRight_Corner].set(SkIntToScalar(topRight.width()),
1884 SkIntToScalar(topRight.height()));
1885 radii[SkRRect::kLowerRight_Corner].set(SkIntToScalar(bottomRight.width()),
1886 SkIntToScalar(bottomRight.height()));
1887 radii[SkRRect::kLowerLeft_Corner].set(SkIntToScalar(bottomLeft.width()),
1888 SkIntToScalar(bottomLeft.height()));
1891 PassRefPtr<SkColorFilter> GraphicsContext::WebCoreColorFilterToSkiaColorFilter(ColorFilter colorFilter)
1893 switch (colorFilter) {
1894 case ColorFilterLuminanceToAlpha:
1895 return adoptRef(SkLumaColorFilter::Create());
1896 case ColorFilterLinearRGBToSRGB:
1897 return ImageBuffer::createColorSpaceFilter(ColorSpaceLinearRGB, ColorSpaceDeviceRGB);
1898 case ColorFilterSRGBToLinearRGB:
1899 return ImageBuffer::createColorSpaceFilter(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
1900 case ColorFilterNone:
1903 ASSERT_NOT_REACHED();
1911 CGColorSpaceRef PLATFORM_EXPORT deviceRGBColorSpaceRef()
1913 static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
1917 void GraphicsContext::draw2xMarker(SkBitmap* bitmap, int index)
1919 const SkPMColor lineColor = lineColors(index);
1920 const SkPMColor antiColor1 = antiColors1(index);
1921 const SkPMColor antiColor2 = antiColors2(index);
1923 uint32_t* row1 = bitmap->getAddr32(0, 0);
1924 uint32_t* row2 = bitmap->getAddr32(0, 1);
1925 uint32_t* row3 = bitmap->getAddr32(0, 2);
1926 uint32_t* row4 = bitmap->getAddr32(0, 3);
1928 // Pattern: X0o o0X0o o0
1932 const SkPMColor row1Color[] = { lineColor, antiColor1, antiColor2, 0, 0, 0, antiColor2, antiColor1 };
1933 const SkPMColor row2Color[] = { lineColor, lineColor, antiColor1, antiColor2, 0, antiColor2, antiColor1, lineColor };
1934 const SkPMColor row3Color[] = { 0, antiColor2, antiColor1, lineColor, lineColor, lineColor, antiColor1, antiColor2 };
1935 const SkPMColor row4Color[] = { 0, 0, antiColor2, antiColor1, lineColor, antiColor1, antiColor2, 0 };
1937 for (int x = 0; x < bitmap->width() + 8; x += 8) {
1938 int count = std::min(bitmap->width() - x, 8);
1940 memcpy(row1 + x, row1Color, count * sizeof(SkPMColor));
1941 memcpy(row2 + x, row2Color, count * sizeof(SkPMColor));
1942 memcpy(row3 + x, row3Color, count * sizeof(SkPMColor));
1943 memcpy(row4 + x, row4Color, count * sizeof(SkPMColor));
1948 void GraphicsContext::draw1xMarker(SkBitmap* bitmap, int index)
1950 const uint32_t lineColor = lineColors(index);
1951 const uint32_t antiColor = antiColors2(index);
1953 // Pattern: X o o X o o X
1955 uint32_t* row1 = bitmap->getAddr32(0, 0);
1956 uint32_t* row2 = bitmap->getAddr32(0, 1);
1957 for (int x = 0; x < bitmap->width(); x++) {
1960 row1[x] = lineColor;
1963 row1[x] = antiColor;
1964 row2[x] = antiColor;
1967 row2[x] = lineColor;
1970 row1[x] = antiColor;
1971 row2[x] = antiColor;
1977 const SkPMColor GraphicsContext::lineColors(int index)
1979 static const SkPMColor colors[] = {
1980 SkPreMultiplyARGB(0xFF, 0xFF, 0x00, 0x00), // Opaque red.
1981 SkPreMultiplyARGB(0xFF, 0xC0, 0xC0, 0xC0) // Opaque gray.
1984 return colors[index];
1987 const SkPMColor GraphicsContext::antiColors1(int index)
1989 static const SkPMColor colors[] = {
1990 SkPreMultiplyARGB(0xB0, 0xFF, 0x00, 0x00), // Semitransparent red.
1991 SkPreMultiplyARGB(0xB0, 0xC0, 0xC0, 0xC0) // Semitransparent gray.
1994 return colors[index];
1997 const SkPMColor GraphicsContext::antiColors2(int index)
1999 static const SkPMColor colors[] = {
2000 SkPreMultiplyARGB(0x60, 0xFF, 0x00, 0x00), // More transparent red
2001 SkPreMultiplyARGB(0x60, 0xC0, 0xC0, 0xC0) // More transparent gray
2004 return colors[index];
2008 void GraphicsContext::setupShader(SkPaint* paint, Gradient* grad, Pattern* pat, SkColor color) const
2010 RefPtr<SkShader> shader;
2013 shader = grad->shader();
2014 color = SK_ColorBLACK;
2016 shader = pat->shader();
2017 color = SK_ColorBLACK;
2018 paint->setFilterBitmap(imageInterpolationQuality() != InterpolationNone);
2021 paint->setColor(m_paintState->applyAlpha(color));
2026 paint->setShader(shader.get());
2029 void GraphicsContext::didDrawTextInRect(const SkRect& textRect)
2031 if (m_trackTextRegion) {
2032 TRACE_EVENT0("skia", "PlatformContextSkia::trackTextRegion");
2033 m_textRegion.join(textRect);