• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "config.h"
26 #include "GraphicsContext.h"
27 
28 #include "AffineTransform.h"
29 #include "Font.h"
30 #include "Gradient.h"
31 #include "NotImplemented.h"
32 #include "Path.h"
33 #include "Pattern.h"
34 #include "PlatformGraphicsContext.h"
35 #include "PlatformGraphicsContextSkia.h"
36 #include "SkBitmapRef.h"
37 #include "SkBlurDrawLooper.h"
38 #include "SkBlurMaskFilter.h"
39 #include "SkCanvas.h"
40 #include "SkColorPriv.h"
41 #include "SkCornerPathEffect.h"
42 #include "SkDashPathEffect.h"
43 #include "SkDevice.h"
44 #include "SkGradientShader.h"
45 #include "SkPaint.h"
46 #include "SkString.h"
47 #include "SkiaUtils.h"
48 #include "TransformationMatrix.h"
49 #include "android_graphics.h"
50 
51 using namespace std;
52 
53 namespace WebCore {
54 
55 // This class just holds onto a PlatformContextSkia for GraphicsContext.
56 class GraphicsContextPlatformPrivate {
57     WTF_MAKE_NONCOPYABLE(GraphicsContextPlatformPrivate);
58 public:
GraphicsContextPlatformPrivate(PlatformGraphicsContext * platformContext)59     GraphicsContextPlatformPrivate(PlatformGraphicsContext* platformContext)
60         : m_context(platformContext) { }
61 
context()62     PlatformGraphicsContext* context() { return m_context; }
63 
64 private:
65     // Non-owning pointer to the PlatformContext.
66     PlatformGraphicsContext* m_context;
67 };
68 
syncPlatformContext(GraphicsContext * gc)69 static void syncPlatformContext(GraphicsContext* gc)
70 {
71     // Stroke and fill sometimes reference each other, so always
72     // sync them both to make sure our state is consistent.
73 
74     PlatformGraphicsContext* pgc = gc->platformContext();
75     Gradient* grad = gc->state().fillGradient.get();
76     Pattern* pat = gc->state().fillPattern.get();
77 
78     if (grad)
79         pgc->setFillShader(grad->platformGradient());
80     else if (pat)
81         pgc->setFillShader(pat->platformPattern(AffineTransform()));
82     else
83         pgc->setFillColor(gc->state().fillColor);
84 
85     grad = gc->state().strokeGradient.get();
86     pat = gc->state().strokePattern.get();
87 
88     if (grad)
89         pgc->setStrokeShader(grad->platformGradient());
90     else if (pat)
91         pgc->setStrokeShader(pat->platformPattern(AffineTransform()));
92     else
93         pgc->setStrokeColor(gc->state().strokeColor);
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////////////////////
97 
createOffscreenContext(int width,int height)98 GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
99 {
100     PlatformGraphicsContextSkia* pgc = new PlatformGraphicsContextSkia(new SkCanvas, true);
101 
102     SkBitmap bitmap;
103 
104     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
105     bitmap.allocPixels();
106     bitmap.eraseColor(0);
107     pgc->getCanvas()->setBitmapDevice(bitmap);
108 
109     GraphicsContext* ctx = new GraphicsContext(pgc);
110     return ctx;
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////////////////////
114 
platformInit(PlatformGraphicsContext * gc)115 void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
116 {
117     if (gc)
118         gc->setGraphicsContext(this);
119     m_data = new GraphicsContextPlatformPrivate(gc);
120     setPaintingDisabled(!gc || gc->isPaintingDisabled());
121 }
122 
platformDestroy()123 void GraphicsContext::platformDestroy()
124 {
125     delete m_data;
126 }
127 
savePlatformState()128 void GraphicsContext::savePlatformState()
129 {
130     if (paintingDisabled())
131         return;
132     platformContext()->save();
133 }
134 
restorePlatformState()135 void GraphicsContext::restorePlatformState()
136 {
137     if (paintingDisabled())
138         return;
139     platformContext()->restore();
140 }
141 
willFill() const142 bool GraphicsContext::willFill() const
143 {
144     return m_state.fillColor.rgb();
145 }
146 
willStroke() const147 bool GraphicsContext::willStroke() const
148 {
149     return m_state.strokeColor.rgb();
150 }
151 
152 // Draws a filled rectangle with a stroked border.
drawRect(const IntRect & rect)153 void GraphicsContext::drawRect(const IntRect& rect)
154 {
155     if (paintingDisabled())
156         return;
157 
158     syncPlatformContext(this);
159     platformContext()->drawRect(rect);
160 }
161 
162 // This is only used to draw borders.
drawLine(const IntPoint & point1,const IntPoint & point2)163 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
164 {
165     if (paintingDisabled())
166         return;
167 
168     syncPlatformContext(this);
169     platformContext()->drawLine(point1, point2);
170 }
171 
drawLineForText(const FloatPoint & pt,float width,bool)172 void GraphicsContext::drawLineForText(const FloatPoint& pt, float width, bool /* printing */)
173 {
174     if (paintingDisabled())
175         return;
176 
177     syncPlatformContext(this);
178     platformContext()->drawLineForText(pt, width);
179 }
180 
drawLineForTextChecking(const FloatPoint & pt,float width,TextCheckingLineStyle style)181 void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width,
182                                               TextCheckingLineStyle style)
183 {
184     if (paintingDisabled())
185         return;
186 
187     syncPlatformContext(this);
188     platformContext()->drawLineForTextChecking(pt, width, style);
189 }
190 
191 // This method is only used to draw the little circles used in lists.
drawEllipse(const IntRect & rect)192 void GraphicsContext::drawEllipse(const IntRect& rect)
193 {
194     if (paintingDisabled())
195         return;
196 
197     syncPlatformContext(this);
198     platformContext()->drawEllipse(rect);
199 }
200 
strokeArc(const IntRect & r,int startAngle,int angleSpan)201 void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
202 {
203     if (paintingDisabled())
204         return;
205 
206     syncPlatformContext(this);
207     platformContext()->strokeArc(r, startAngle, angleSpan);
208 }
209 
drawConvexPolygon(size_t numPoints,const FloatPoint * points,bool shouldAntialias)210 void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points,
211                                         bool shouldAntialias)
212 {
213     if (paintingDisabled())
214         return;
215 
216     syncPlatformContext(this);
217     platformContext()->drawConvexPolygon(numPoints, points, shouldAntialias);
218 }
219 
fillRoundedRect(const IntRect & rect,const IntSize & topLeft,const IntSize & topRight,const IntSize & bottomLeft,const IntSize & bottomRight,const Color & color,ColorSpace colorSpace)220 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
221                                       const IntSize& bottomLeft, const IntSize& bottomRight,
222                                       const Color& color, ColorSpace colorSpace)
223 {
224     if (paintingDisabled())
225         return;
226 
227     syncPlatformContext(this);
228     platformContext()->fillRoundedRect(rect, topLeft, topRight,
229             bottomLeft, bottomRight, color, colorSpace);
230 }
231 
fillRect(const FloatRect & rect)232 void GraphicsContext::fillRect(const FloatRect& rect)
233 {
234     if (paintingDisabled())
235         return;
236 
237     syncPlatformContext(this);
238     platformContext()->fillRect(rect);
239 }
240 
fillRect(const FloatRect & rect,const Color & color,ColorSpace colorSpace)241 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
242 {
243     if (paintingDisabled())
244         return;
245 
246     syncPlatformContext(this);
247     platformContext()->fillRect(rect, color, colorSpace);
248 }
249 
clip(const FloatRect & rect)250 void GraphicsContext::clip(const FloatRect& rect)
251 {
252     if (paintingDisabled())
253         return;
254 
255     platformContext()->clip(rect);
256 }
257 
clip(const Path & path)258 void GraphicsContext::clip(const Path& path)
259 {
260     if (paintingDisabled())
261         return;
262 
263     platformContext()->clip(path);
264 }
265 
addInnerRoundedRectClip(const IntRect & rect,int thickness)266 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
267 {
268     if (paintingDisabled())
269         return;
270 
271     platformContext()->addInnerRoundedRectClip(rect, thickness);
272 }
273 
canvasClip(const Path & path)274 void GraphicsContext::canvasClip(const Path& path)
275 {
276     if (paintingDisabled())
277         return;
278 
279     platformContext()->canvasClip(path);
280 }
281 
clipOut(const IntRect & r)282 void GraphicsContext::clipOut(const IntRect& r)
283 {
284     if (paintingDisabled())
285         return;
286 
287     platformContext()->clipOut(r);
288 }
289 
290 #if ENABLE(SVG)
clipPath(const Path & pathToClip,WindRule clipRule)291 void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
292 {
293     if (paintingDisabled())
294         return;
295 
296     platformContext()->clipPath(pathToClip, clipRule);
297 }
298 #endif
299 
clipOut(const Path & p)300 void GraphicsContext::clipOut(const Path& p)
301 {
302     if (paintingDisabled())
303         return;
304 
305     platformContext()->clipOut(p);
306 }
307 
308 //////////////////////////////////////////////////////////////////////////////////////////////////
309 
310 #if SVG_SUPPORT
createRenderingDeviceContext()311 KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext()
312 {
313     return new KRenderingDeviceContextQuartz(platformContext());
314 }
315 #endif
316 
beginTransparencyLayer(float opacity)317 void GraphicsContext::beginTransparencyLayer(float opacity)
318 {
319     if (paintingDisabled())
320         return;
321 
322     platformContext()->beginTransparencyLayer(opacity);
323 }
324 
endTransparencyLayer()325 void GraphicsContext::endTransparencyLayer()
326 {
327     if (paintingDisabled())
328         return;
329 
330     platformContext()->endTransparencyLayer();
331 }
332 
333 ///////////////////////////////////////////////////////////////////////////
334 
setupFillPaint(SkPaint * paint)335 void GraphicsContext::setupFillPaint(SkPaint* paint)
336 {
337     if (paintingDisabled())
338         return;
339     syncPlatformContext(this);
340     platformContext()->setupPaintFill(paint);
341 }
342 
setupStrokePaint(SkPaint * paint)343 void GraphicsContext::setupStrokePaint(SkPaint* paint)
344 {
345     if (paintingDisabled())
346         return;
347     syncPlatformContext(this);
348     platformContext()->setupPaintStroke(paint, 0);
349 }
350 
setupShadowPaint(SkPaint * paint,SkPoint * offset)351 bool GraphicsContext::setupShadowPaint(SkPaint* paint, SkPoint* offset)
352 {
353     if (paintingDisabled())
354         return false;
355     syncPlatformContext(this);
356     return platformContext()->setupPaintShadow(paint, offset);
357 }
358 
setPlatformStrokeColor(const Color & c,ColorSpace)359 void GraphicsContext::setPlatformStrokeColor(const Color& c, ColorSpace)
360 {
361 }
362 
setPlatformStrokeThickness(float f)363 void GraphicsContext::setPlatformStrokeThickness(float f)
364 {
365     if (paintingDisabled())
366         return;
367     platformContext()->setStrokeThickness(f);
368 }
369 
setPlatformStrokeStyle(StrokeStyle style)370 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle style)
371 {
372     if (paintingDisabled())
373         return;
374     platformContext()->setStrokeStyle(style);
375 }
376 
setPlatformFillColor(const Color & c,ColorSpace)377 void GraphicsContext::setPlatformFillColor(const Color& c, ColorSpace)
378 {
379 }
380 
setPlatformShadow(const FloatSize & size,float blur,const Color & color,ColorSpace)381 void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace)
382 {
383     if (paintingDisabled())
384         return;
385 
386     if (blur <= 0)
387         this->clearPlatformShadow();
388 
389     SkColor c;
390     if (color.isValid())
391         c = color.rgb();
392     else
393         c = SkColorSetARGB(0xFF / 3, 0, 0, 0); // "std" Apple shadow color
394     platformContext()->setShadow(blur, size.width(), size.height(), c);
395 }
396 
clearPlatformShadow()397 void GraphicsContext::clearPlatformShadow()
398 {
399     if (paintingDisabled())
400         return;
401 
402     platformContext()->setShadow(0, 0, 0, 0);
403 }
404 
405 ///////////////////////////////////////////////////////////////////////////////
406 
drawFocusRing(const Vector<IntRect> & rects,int width,int offset,const Color & color)407 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
408 {
409     if (paintingDisabled())
410         return;
411 
412     syncPlatformContext(this);
413     platformContext()->drawFocusRing(rects, width, offset, color);
414 }
415 
drawFocusRing(const Path &,int,int,const Color &)416 void GraphicsContext::drawFocusRing(const Path&, int, int, const Color&)
417 {
418     // Do nothing, since we draw the focus ring independently.
419 }
420 
platformContext() const421 PlatformGraphicsContext* GraphicsContext::platformContext() const
422 {
423     ASSERT(!paintingDisabled());
424     return m_data->context();
425 }
426 
setMiterLimit(float limit)427 void GraphicsContext::setMiterLimit(float limit)
428 {
429     if (paintingDisabled())
430         return;
431     platformContext()->setMiterLimit(limit);
432 }
433 
setAlpha(float alpha)434 void GraphicsContext::setAlpha(float alpha)
435 {
436     if (paintingDisabled())
437         return;
438     platformContext()->setAlpha(alpha);
439 }
440 
setPlatformCompositeOperation(CompositeOperator op)441 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
442 {
443     if (paintingDisabled())
444         return;
445     platformContext()->setCompositeOperation(op);
446 }
447 
clearRect(const FloatRect & rect)448 void GraphicsContext::clearRect(const FloatRect& rect)
449 {
450     if (paintingDisabled())
451         return;
452 
453     syncPlatformContext(this);
454     platformContext()->clearRect(rect);
455 }
456 
strokeRect(const FloatRect & rect,float lineWidth)457 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
458 {
459     if (paintingDisabled())
460         return;
461 
462     syncPlatformContext(this);
463     platformContext()->strokeRect(rect, lineWidth);
464 }
465 
setLineCap(LineCap cap)466 void GraphicsContext::setLineCap(LineCap cap)
467 {
468     if (paintingDisabled())
469         return;
470     platformContext()->setLineCap(cap);
471 }
472 
473 #if ENABLE(SVG)
setLineDash(const DashArray & dashes,float dashOffset)474 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
475 {
476     if (paintingDisabled())
477         return;
478 
479     platformContext()->setLineDash(dashes, dashOffset);
480 }
481 #endif
482 
setLineJoin(LineJoin join)483 void GraphicsContext::setLineJoin(LineJoin join)
484 {
485     if (paintingDisabled())
486         return;
487     platformContext()->setLineJoin(join);
488 }
489 
scale(const FloatSize & size)490 void GraphicsContext::scale(const FloatSize& size)
491 {
492     if (paintingDisabled())
493         return;
494     platformContext()->scale(size);
495 }
496 
rotate(float angleInRadians)497 void GraphicsContext::rotate(float angleInRadians)
498 {
499     if (paintingDisabled())
500         return;
501     platformContext()->rotate(angleInRadians);
502 }
503 
translate(float x,float y)504 void GraphicsContext::translate(float x, float y)
505 {
506     if (paintingDisabled())
507         return;
508     platformContext()->translate(x, y);
509 }
510 
concatCTM(const AffineTransform & affine)511 void GraphicsContext::concatCTM(const AffineTransform& affine)
512 {
513     if (paintingDisabled())
514         return;
515     platformContext()->concatCTM(affine);
516 }
517 
518 // This is intended to round the rect to device pixels (through the CTM)
519 // and then invert the result back into source space, with the hope that when
520 // it is drawn (through the matrix), it will land in the "right" place (i.e.
521 // on pixel boundaries).
522 
523 // For android, we record this geometry once and then draw it though various
524 // scale factors as the user zooms, without re-recording. Thus this routine
525 // should just leave the original geometry alone.
526 
527 // If we instead draw into bitmap tiles, we should then perform this
528 // transform -> round -> inverse step.
529 
roundToDevicePixels(const FloatRect & rect,RoundingMode)530 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode)
531 {
532     return rect;
533 }
534 
535 //////////////////////////////////////////////////////////////////////////////////////////////////
536 
setURLForRect(const KURL & link,const IntRect & destRect)537 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
538 {
539 // Appears to be PDF specific, so we ignore it
540 }
541 
setPlatformShouldAntialias(bool useAA)542 void GraphicsContext::setPlatformShouldAntialias(bool useAA)
543 {
544     if (paintingDisabled())
545         return;
546     platformContext()->setShouldAntialias(useAA);
547 }
548 
setPlatformFillGradient(Gradient * fillGradient)549 void GraphicsContext::setPlatformFillGradient(Gradient* fillGradient)
550 {
551 }
552 
setPlatformFillPattern(Pattern * fillPattern)553 void GraphicsContext::setPlatformFillPattern(Pattern* fillPattern)
554 {
555 }
556 
setPlatformStrokeGradient(Gradient * strokeGradient)557 void GraphicsContext::setPlatformStrokeGradient(Gradient* strokeGradient)
558 {
559 }
560 
setPlatformStrokePattern(Pattern * strokePattern)561 void GraphicsContext::setPlatformStrokePattern(Pattern* strokePattern)
562 {
563 }
564 
getCTM() const565 AffineTransform GraphicsContext::getCTM() const
566 {
567     if (paintingDisabled())
568         return AffineTransform();
569     const SkMatrix& m = platformContext()->getTotalMatrix();
570     return AffineTransform(SkScalarToDouble(m.getScaleX()), // a
571                            SkScalarToDouble(m.getSkewY()), // b
572                            SkScalarToDouble(m.getSkewX()), // c
573                            SkScalarToDouble(m.getScaleY()), // d
574                            SkScalarToDouble(m.getTranslateX()), // e
575                            SkScalarToDouble(m.getTranslateY())); // f
576 }
577 
setCTM(const AffineTransform & transform)578 void GraphicsContext::setCTM(const AffineTransform& transform)
579 {
580     // The SkPicture mode of Skia does not support SkCanvas::setMatrix(), so we
581     // can not simply use that method here. We could calculate the transform
582     // required to achieve the desired matrix and use SkCanvas::concat(), but
583     // there's currently no need for this.
584     ASSERT_NOT_REACHED();
585 }
586 
587 ///////////////////////////////////////////////////////////////////////////////
588 
fillPath(const Path & pathToFill)589 void GraphicsContext::fillPath(const Path& pathToFill)
590 {
591     if (paintingDisabled())
592         return;
593 
594     syncPlatformContext(this);
595     platformContext()->fillPath(pathToFill, fillRule());
596 }
597 
strokePath(const Path & pathToStroke)598 void GraphicsContext::strokePath(const Path& pathToStroke)
599 {
600     if (paintingDisabled())
601         return;
602 
603     syncPlatformContext(this);
604     platformContext()->strokePath(pathToStroke);
605 }
606 
imageInterpolationQuality() const607 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
608 {
609     notImplemented();
610     return InterpolationDefault;
611 }
612 
setImageInterpolationQuality(InterpolationQuality mode)613 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
614 {
615 #if 0
616     enum InterpolationQuality {
617         InterpolationDefault,
618         InterpolationNone,
619         InterpolationLow,
620         InterpolationMedium,
621         InterpolationHigh
622     };
623 #endif
624     // TODO: record this, so we can know when to use bitmap-filtering when we draw
625     // ... not sure how meaningful this will be given our playback model.
626 
627     // Certainly safe to do nothing for the present.
628 }
629 
clipConvexPolygon(size_t numPoints,const FloatPoint *,bool antialias)630 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint*,
631                                         bool antialias)
632 {
633     if (paintingDisabled())
634         return;
635 
636     if (numPoints <= 1)
637         return;
638 
639     // FIXME: IMPLEMENT!
640 }
641 
drawHighlightForText(const Font & font,const TextRun & run,const FloatPoint & point,int h,const Color & backgroundColor,ColorSpace colorSpace,int from,int to,bool isActive)642 void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run,
643                                            const FloatPoint& point, int h,
644                                            const Color& backgroundColor,
645                                            ColorSpace colorSpace, int from,
646                                            int to, bool isActive)
647 {
648     if (paintingDisabled())
649         return;
650 
651     syncPlatformContext(this);
652     platformContext()->drawHighlightForText(font, run, point, h, backgroundColor,
653             colorSpace, from, to, isActive);
654 }
655 
656 } // namespace WebCore
657 
658 ///////////////////////////////////////////////////////////////////////////////
659 
android_gc2canvas(WebCore::GraphicsContext * gc)660 SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc)
661 {
662     return gc->platformContext()->getCanvas();
663 }
664