Ownership of canvas's GraphicsContext3D should be moved to PlatformContextSkia
[WebKit-https.git] / Source / WebCore / platform / graphics / skia / GraphicsContextSkia.cpp
1 /*
2  * Copyright (c) 2006, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "GraphicsContext.h"
33
34 #include "AffineTransform.h"
35 #include "Color.h"
36 #include "FloatRect.h"
37 #include "Gradient.h"
38 #include "ImageBuffer.h"
39 #include "IntRect.h"
40 #include "NativeImageSkia.h"
41 #include "NotImplemented.h"
42 #include "PlatformContextSkia.h"
43
44 #include "SkBitmap.h"
45 #include "SkBlurMaskFilter.h"
46 #include "SkColorFilter.h"
47 #include "SkCornerPathEffect.h"
48 #include "SkLayerDrawLooper.h"
49 #include "SkShader.h"
50 #include "SkiaUtils.h"
51 #include "skia/ext/platform_canvas.h"
52
53 #include <math.h>
54 #include <wtf/Assertions.h>
55 #include <wtf/MathExtras.h>
56 #include <wtf/UnusedParam.h>
57
58 #if PLATFORM(CHROMIUM) && OS(DARWIN)
59 #include <CoreGraphics/CGColorSpace.h>
60 #endif
61
62 using namespace std;
63
64 namespace WebCore {
65
66 namespace {
67
68 inline int fastMod(int value, int max)
69 {
70     int sign = SkExtractSign(value);
71
72     value = SkApplySign(value, sign);
73     if (value >= max)
74         value %= max;
75     return SkApplySign(value, sign);
76 }
77
78 inline float square(float n)
79 {
80     return n * n;
81 }
82
83 }  // namespace
84
85 // "Seatbelt" functions ------------------------------------------------------
86 //
87 // These functions check certain graphics primitives for being "safe".
88 // Skia has historically crashed when sent crazy data. These functions do
89 // additional checking to prevent crashes.
90 //
91 // Ideally, all of these would be fixed in the graphics layer and we would not
92 // have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA
93 // flag to check the graphics layer.
94
95 // Disabling these checks (20/01/2010), since we think we've fixed all the Skia
96 // bugs.  Leaving the code in for now, so we can revert easily if necessary.
97 // #define ENSURE_VALUE_SAFETY_FOR_SKIA
98
99 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
100 static bool isCoordinateSkiaSafe(float coord)
101 {
102     // First check for valid floats.
103 #if defined(_MSC_VER)
104     if (!_finite(coord))
105 #else
106     if (!finite(coord))
107 #endif
108         return false;
109
110     // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If
111     // the transformed point exceeds 15 bits, we just declare that it's
112     // unreasonable to catch both of these cases.
113     static const int maxPointMagnitude = 32767;
114     if (coord > maxPointMagnitude || coord < -maxPointMagnitude)
115         return false;
116
117     return true;
118 }
119 #endif
120
121 static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt)
122 {
123 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
124     // Now check for points that will overflow. We check the *transformed*
125     // points since this is what will be rasterized.
126     SkPoint xPt;
127     transform.mapPoints(&xPt, &pt, 1);
128     return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);
129 #else
130     return true;
131 #endif
132 }
133
134 static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc)
135 {
136 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
137     SkPoint topleft = {rc.fLeft, rc.fTop};
138     SkPoint bottomright = {rc.fRight, rc.fBottom};
139     return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);
140 #else
141     return true;
142 #endif
143 }
144
145 bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path)
146 {
147 #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
148     SkPoint current_points[4];
149     SkPath::Iter iter(path, false);
150     for (SkPath::Verb verb = iter.next(current_points);
151          verb != SkPath::kDone_Verb;
152          verb = iter.next(current_points)) {
153         switch (verb) {
154         case SkPath::kMove_Verb:
155             // This move will be duplicated in the next verb, so we can ignore.
156             break;
157         case SkPath::kLine_Verb:
158             // iter.next returns 2 points.
159             if (!isPointSkiaSafe(transform, current_points[0])
160                 || !isPointSkiaSafe(transform, current_points[1]))
161                 return false;
162             break;
163         case SkPath::kQuad_Verb:
164             // iter.next returns 3 points.
165             if (!isPointSkiaSafe(transform, current_points[0])
166                 || !isPointSkiaSafe(transform, current_points[1])
167                 || !isPointSkiaSafe(transform, current_points[2]))
168                 return false;
169             break;
170         case SkPath::kCubic_Verb:
171             // iter.next returns 4 points.
172             if (!isPointSkiaSafe(transform, current_points[0])
173                 || !isPointSkiaSafe(transform, current_points[1])
174                 || !isPointSkiaSafe(transform, current_points[2])
175                 || !isPointSkiaSafe(transform, current_points[3]))
176                 return false;
177             break;
178         case SkPath::kClose_Verb:
179         case SkPath::kDone_Verb:
180         default:
181             break;
182         }
183     }
184     return true;
185 #else
186     return true;
187 #endif
188 }
189
190 // Local helper functions ------------------------------------------------------
191
192 void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
193 {
194     SkIRect ir;
195     int rx = SkMin32(SkScalarRound(rect.width()), size.width());
196     int ry = SkMin32(SkScalarRound(rect.height()), size.height());
197
198     ir.set(-rx, -ry, rx, ry);
199     switch (startAngle) {
200     case 0:
201         ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
202         break;
203     case 90:
204         ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
205         break;
206     case 180:
207         ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
208         break;
209     case 270:
210         ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
211         break;
212     default:
213         ASSERT(0);
214     }
215
216     SkRect r;
217     r.set(ir);
218     path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
219 }
220
221 // -----------------------------------------------------------------------------
222
223 // This may be called with a NULL pointer to create a graphics context that has
224 // no painting.
225 void GraphicsContext::platformInit(PlatformGraphicsContext* gc)
226 {
227     if (gc)
228         gc->setGraphicsContext(this);
229
230     // the caller owns the gc
231     m_data = gc;
232     setPaintingDisabled(!gc || !gc->canvas());
233 }
234
235 void GraphicsContext::platformDestroy()
236 {
237 }
238
239 PlatformGraphicsContext* GraphicsContext::platformContext() const
240 {
241     ASSERT(!paintingDisabled());
242     return m_data;
243 }
244
245 // State saving ----------------------------------------------------------------
246
247 void GraphicsContext::savePlatformState()
248 {
249     if (paintingDisabled())
250         return;
251
252     // Save our private State.
253     platformContext()->save();
254 }
255
256 void GraphicsContext::restorePlatformState()
257 {
258     if (paintingDisabled())
259         return;
260
261     // Restore our private State.
262     platformContext()->restore();
263 }
264
265 void GraphicsContext::beginTransparencyLayer(float opacity)
266 {
267     if (paintingDisabled())
268         return;
269
270     // We need the "alpha" layer flag here because the base layer is opaque
271     // (the surface of the page) but layers on top may have transparent parts.
272     // Without explicitly setting the alpha flag, the layer will inherit the
273     // opaque setting of the base and some things won't work properly.
274     platformContext()->canvas()->saveLayerAlpha(
275         0,
276         static_cast<unsigned char>(opacity * 255),
277         static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
278                                          SkCanvas::kFullColorLayer_SaveFlag));
279 }
280
281 void GraphicsContext::endTransparencyLayer()
282 {
283     if (paintingDisabled())
284         return;
285     platformContext()->canvas()->restore();
286 }
287
288 // Graphics primitives ---------------------------------------------------------
289
290 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
291 {
292     if (paintingDisabled())
293         return;
294
295     SkRect r(rect);
296     if (!isRectSkiaSafe(getCTM(), r))
297         return;
298
299     SkPath path;
300     path.addOval(r, SkPath::kCW_Direction);
301     // only perform the inset if we won't invert r
302     if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
303         // Adding one to the thickness doesn't make the border too thick as
304         // it's painted over afterwards. But without this adjustment the
305         // border appears a little anemic after anti-aliasing.
306         r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
307         path.addOval(r, SkPath::kCCW_Direction);
308     }
309     platformContext()->clipPathAntiAliased(path);
310 }
311
312 void GraphicsContext::clearPlatformShadow()
313 {
314     if (paintingDisabled())
315         return;
316     platformContext()->setDrawLooper(0);
317 }
318
319 void GraphicsContext::clearRect(const FloatRect& rect)
320 {
321     if (paintingDisabled())
322         return;
323
324     SkRect r = rect;
325     if (!isRectSkiaSafe(getCTM(), r))
326         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
327
328     platformContext()->makeGrContextCurrent();
329
330     SkPaint paint;
331     platformContext()->setupPaintForFilling(&paint);
332     paint.setXfermodeMode(SkXfermode::kClear_Mode);
333     platformContext()->canvas()->drawRect(r, paint);
334 }
335
336 void GraphicsContext::clip(const FloatRect& rect)
337 {
338     if (paintingDisabled())
339         return;
340
341     SkRect r(rect);
342     if (!isRectSkiaSafe(getCTM(), r))
343         return;
344
345     platformContext()->makeGrContextCurrent();
346     platformContext()->canvas()->clipRect(r);
347 }
348
349 void GraphicsContext::clip(const Path& path)
350 {
351     if (paintingDisabled())
352         return;
353
354     const SkPath& p = *path.platformPath();
355     if (!isPathSkiaSafe(getCTM(), p))
356         return;
357
358     platformContext()->clipPathAntiAliased(p);
359 }
360
361 void GraphicsContext::canvasClip(const Path& path)
362 {
363     if (paintingDisabled())
364         return;
365
366     const SkPath& p = *path.platformPath();
367     if (!isPathSkiaSafe(getCTM(), p))
368         return;
369
370     platformContext()->canvasClipPath(p);
371 }
372
373 void GraphicsContext::clipOut(const IntRect& rect)
374 {
375     if (paintingDisabled())
376         return;
377
378     SkRect r(rect);
379     if (!isRectSkiaSafe(getCTM(), r))
380         return;
381
382     platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
383 }
384
385 void GraphicsContext::clipOut(const Path& p)
386 {
387     if (paintingDisabled())
388         return;
389
390     const SkPath& path = *p.platformPath();
391     if (!isPathSkiaSafe(getCTM(), path))
392         return;
393
394     platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
395 }
396
397 void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
398 {
399     if (paintingDisabled())
400         return;
401
402     SkPath path = *pathToClip.platformPath();
403     if (!isPathSkiaSafe(getCTM(), path))
404         return;
405
406     path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
407     platformContext()->clipPathAntiAliased(path);
408 }
409
410 void GraphicsContext::concatCTM(const AffineTransform& affine)
411 {
412     if (paintingDisabled())
413         return;
414
415     platformContext()->canvas()->concat(affine);
416 }
417
418 void GraphicsContext::setCTM(const AffineTransform& affine)
419 {
420     if (paintingDisabled())
421         return;
422
423     platformContext()->canvas()->setMatrix(affine);
424 }
425
426 static void setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points)
427 {
428     path->incReserve(numPoints);
429     path->moveTo(WebCoreFloatToSkScalar(points[0].x()),
430                  WebCoreFloatToSkScalar(points[0].y()));
431     for (size_t i = 1; i < numPoints; ++i) {
432         path->lineTo(WebCoreFloatToSkScalar(points[i].x()),
433                      WebCoreFloatToSkScalar(points[i].y()));
434     }
435     path->setIsConvex(true);
436 }
437
438 void GraphicsContext::drawConvexPolygon(size_t numPoints,
439                                         const FloatPoint* points,
440                                         bool shouldAntialias)
441 {
442     if (paintingDisabled())
443         return;
444
445     if (numPoints <= 1)
446         return;
447
448     platformContext()->makeGrContextCurrent();
449
450     SkPath path;
451     setPathFromConvexPoints(&path, numPoints, points);
452
453     if (!isPathSkiaSafe(getCTM(), path))
454         return;
455
456     SkPaint paint;
457     platformContext()->setupPaintForFilling(&paint);
458     paint.setAntiAlias(shouldAntialias);
459     platformContext()->canvas()->drawPath(path, paint);
460
461     if (strokeStyle() != NoStroke) {
462         paint.reset();
463         platformContext()->setupPaintForStroking(&paint, 0, 0);
464         platformContext()->canvas()->drawPath(path, paint);
465     }
466 }
467
468 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
469 {
470     if (paintingDisabled())
471         return;
472
473     if (numPoints <= 1)
474         return;
475
476     SkPath path;
477     setPathFromConvexPoints(&path, numPoints, points);
478     platformContext()->canvas()->clipPath(path);
479 }
480
481 // This method is only used to draw the little circles used in lists.
482 void GraphicsContext::drawEllipse(const IntRect& elipseRect)
483 {
484     if (paintingDisabled())
485         return;
486
487     SkRect rect = elipseRect;
488     if (!isRectSkiaSafe(getCTM(), rect))
489         return;
490
491     platformContext()->makeGrContextCurrent();
492     SkPaint paint;
493     platformContext()->setupPaintForFilling(&paint);
494     platformContext()->canvas()->drawOval(rect, paint);
495
496     if (strokeStyle() != NoStroke) {
497         paint.reset();
498         platformContext()->setupPaintForStroking(&paint, &rect, 0);
499         platformContext()->canvas()->drawOval(rect, paint);
500     }
501 }
502
503 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
504 {
505     // FIXME: implement
506 }
507
508 static inline void drawOuterPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width)
509 {
510 #if PLATFORM(CHROMIUM) && OS(DARWIN)
511     paint.setAlpha(64);
512     paint.setStrokeWidth(width);
513     paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref();
514 #else
515     paint.setStrokeWidth(1);
516     paint.setPathEffect(new SkCornerPathEffect(1))->unref();
517 #endif
518     canvas->drawPath(path, paint);
519 }
520
521 static inline void drawInnerPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width)
522 {
523 #if PLATFORM(CHROMIUM) && OS(DARWIN)
524     paint.setAlpha(128);
525     paint.setStrokeWidth(width * 0.5f);
526     canvas->drawPath(path, paint);
527 #endif
528 }
529
530 static inline SkScalar getFocusRingOutset(int width)
531 {
532 #if PLATFORM(CHROMIUM) && OS(DARWIN)
533     return (width * 0.5f) + 0.25f;
534 #else
535     return 0.5f;
536 #endif
537 }
538
539 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color)
540 {
541     if (paintingDisabled())
542         return;
543
544     unsigned rectCount = rects.size();
545     if (!rectCount)
546         return;
547
548     platformContext()->makeGrContextCurrent();
549     SkRegion focusRingRegion;
550     const SkScalar focusRingOutset = getFocusRingOutset(width);
551     for (unsigned i = 0; i < rectCount; i++) {
552         SkIRect r = rects[i];
553         r.inset(-focusRingOutset, -focusRingOutset);
554         focusRingRegion.op(r, SkRegion::kUnion_Op);
555     }
556
557     SkPath path;
558     SkPaint paint;
559     paint.setAntiAlias(true);
560     paint.setStyle(SkPaint::kStroke_Style);
561
562     paint.setColor(color.rgb());
563     focusRingRegion.getBoundaryPath(&path);
564     SkCanvas* canvas = platformContext()->canvas();
565     drawOuterPath(canvas, path, paint, width);
566     drawInnerPath(canvas, path, paint, width);
567 }
568
569 // This is only used to draw borders.
570 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
571 {
572     if (paintingDisabled())
573         return;
574
575     StrokeStyle penStyle = strokeStyle();
576     if (penStyle == NoStroke)
577         return;
578
579     SkPaint paint;
580     if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
581         return;
582
583     platformContext()->makeGrContextCurrent();
584
585     FloatPoint p1 = point1;
586     FloatPoint p2 = point2;
587     bool isVerticalLine = (p1.x() == p2.x());
588     int width = roundf(strokeThickness());
589
590     // We know these are vertical or horizontal lines, so the length will just
591     // be the sum of the displacement component vectors give or take 1 -
592     // probably worth the speed up of no square root, which also won't be exact.
593     FloatSize disp = p2 - p1;
594     int length = SkScalarRound(disp.width() + disp.height());
595     platformContext()->setupPaintForStroking(&paint, 0, length);
596
597     if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
598         // Do a rect fill of our endpoints.  This ensures we always have the
599         // appearance of being a border.  We then draw the actual dotted/dashed line.
600
601         SkRect r1, r2;
602         r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
603         r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
604
605         if (isVerticalLine) {
606             r1.offset(-width / 2, 0);
607             r2.offset(-width / 2, -width);
608         } else {
609             r1.offset(0, -width / 2);
610             r2.offset(-width, -width / 2);
611         }
612         SkPaint fillPaint;
613         fillPaint.setColor(paint.getColor());
614         platformContext()->canvas()->drawRect(r1, fillPaint);
615         platformContext()->canvas()->drawRect(r2, fillPaint);
616     }
617
618     adjustLineToPixelBoundaries(p1, p2, width, penStyle);
619     SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
620
621     platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
622 }
623
624 void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle style)
625 {
626     if (paintingDisabled())
627         return;
628
629     platformContext()->makeGrContextCurrent();
630
631     // Create the pattern we'll use to draw the underline.
632     static SkBitmap* misspellBitmap = 0;
633     if (!misspellBitmap) {
634         // We use a 2-pixel-high misspelling indicator because that seems to be
635         // what WebKit is designed for, and how much room there is in a typical
636         // page for it.
637         const int rowPixels = 32;  // Must be multiple of 4 for pattern below.
638         const int colPixels = 2;
639         misspellBitmap = new SkBitmap;
640         misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
641                                    rowPixels, colPixels);
642         misspellBitmap->allocPixels();
643
644         misspellBitmap->eraseARGB(0, 0, 0, 0);
645         const uint32_t lineColor = 0xFFFF0000;  // Opaque red.
646         const uint32_t antiColor = 0x60600000;  // Semitransparent red.
647
648         // Pattern:  X o   o X o   o X
649         //             o X o   o X o
650         uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
651         uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
652         for (int x = 0; x < rowPixels; x++) {
653             switch (x % 4) {
654             case 0:
655                 row1[x] = lineColor;
656                 break;
657             case 1:
658                 row1[x] = antiColor;
659                 row2[x] = antiColor;
660                 break;
661             case 2:
662                 row2[x] = lineColor;
663                 break;
664             case 3:
665                 row1[x] = antiColor;
666                 row2[x] = antiColor;
667                 break;
668             }
669         }
670     }
671
672     // Offset it vertically by 1 so that there's some space under the text.
673     SkScalar originX = WebCoreFloatToSkScalar(pt.x());
674     SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
675
676     // Make a shader for the bitmap with an origin of the box we'll draw. This
677     // shader is refcounted and will have an initial refcount of 1.
678     SkShader* shader = SkShader::CreateBitmapShader(
679         *misspellBitmap, SkShader::kRepeat_TileMode,
680         SkShader::kRepeat_TileMode);
681     SkMatrix matrix;
682     matrix.reset();
683     matrix.postTranslate(originX, originY);
684     shader->setLocalMatrix(matrix);
685
686     // Assign the shader to the paint & release our reference. The paint will
687     // now own the shader and the shader will be destroyed when the paint goes
688     // out of scope.
689     SkPaint paint;
690     paint.setShader(shader);
691     shader->unref();
692
693     SkRect rect;
694     rect.set(originX,
695              originY,
696              originX + WebCoreFloatToSkScalar(width),
697              originY + SkIntToScalar(misspellBitmap->height()));
698     platformContext()->canvas()->drawRect(rect, paint);
699 }
700
701 void GraphicsContext::drawLineForText(const FloatPoint& pt,
702                                       float width,
703                                       bool printing)
704 {
705     if (paintingDisabled())
706         return;
707
708     if (width <= 0)
709         return;
710
711     platformContext()->makeGrContextCurrent();
712
713     int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
714     SkRect r;
715     r.fLeft = WebCoreFloatToSkScalar(pt.x());
716     r.fTop = WebCoreFloatToSkScalar(pt.y());
717     r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
718     r.fBottom = r.fTop + SkIntToScalar(thickness);
719
720     SkPaint paint;
721     platformContext()->setupPaintForFilling(&paint);
722     // Text lines are drawn using the stroke color.
723     paint.setColor(platformContext()->effectiveStrokeColor());
724     platformContext()->canvas()->drawRect(r, paint);
725 }
726
727 // Draws a filled rectangle with a stroked border.
728 void GraphicsContext::drawRect(const IntRect& rect)
729 {
730     if (paintingDisabled())
731         return;
732
733     platformContext()->makeGrContextCurrent();
734
735     SkRect r = rect;
736     if (!isRectSkiaSafe(getCTM(), r)) {
737         // See the fillRect below.
738         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
739     }
740
741     platformContext()->drawRect(r);
742 }
743
744 void GraphicsContext::fillPath(const Path& pathToFill)
745 {
746     if (paintingDisabled())
747         return;
748
749     SkPath path = *pathToFill.platformPath();
750     if (!isPathSkiaSafe(getCTM(), path))
751       return;
752
753     platformContext()->makeGrContextCurrent();
754
755     const GraphicsContextState& state = m_state;
756     path.setFillType(state.fillRule == RULE_EVENODD ?
757         SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
758
759     SkPaint paint;
760     platformContext()->setupPaintForFilling(&paint);
761
762     platformContext()->canvas()->drawPath(path, paint);
763 }
764
765 void GraphicsContext::fillRect(const FloatRect& rect)
766 {
767     if (paintingDisabled())
768         return;
769
770     SkRect r = rect;
771     if (!isRectSkiaSafe(getCTM(), r)) {
772         // See the other version of fillRect below.
773         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
774     }
775
776     platformContext()->save();
777
778     platformContext()->makeGrContextCurrent();
779
780     SkPaint paint;
781     platformContext()->setupPaintForFilling(&paint);
782     platformContext()->canvas()->drawRect(r, paint);
783
784     platformContext()->restore();
785 }
786
787 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
788 {
789     if (paintingDisabled())
790         return;
791
792     platformContext()->makeGrContextCurrent();
793
794     SkRect r = rect;
795     if (!isRectSkiaSafe(getCTM(), r)) {
796         // Special case when the rectangle overflows fixed point. This is a
797         // workaround to fix bug 1212844. When the input rectangle is very
798         // large, it can overflow Skia's internal fixed point rect. This
799         // should be fixable in Skia (since the output bitmap isn't that
800         // large), but until that is fixed, we try to handle it ourselves.
801         //
802         // We manually clip the rectangle to the current clip rect. This
803         // will prevent overflow. The rectangle will be transformed to the
804         // canvas' coordinate space before it is converted to fixed point
805         // so we are guaranteed not to overflow after doing this.
806         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
807     }
808
809     SkPaint paint;
810     platformContext()->setupPaintCommon(&paint);
811     paint.setColor(color.rgb());
812     platformContext()->canvas()->drawRect(r, paint);
813 }
814
815 void GraphicsContext::fillRoundedRect(const IntRect& rect,
816                                       const IntSize& topLeft,
817                                       const IntSize& topRight,
818                                       const IntSize& bottomLeft,
819                                       const IntSize& bottomRight,
820                                       const Color& color,
821                                       ColorSpace colorSpace)
822 {
823     if (paintingDisabled())
824         return;
825
826     platformContext()->makeGrContextCurrent();
827
828     SkRect r = rect;
829     if (!isRectSkiaSafe(getCTM(), r))
830         // See fillRect().
831         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
832
833     if (topLeft.width() + topRight.width() > rect.width()
834             || bottomLeft.width() + bottomRight.width() > rect.width()
835             || topLeft.height() + bottomLeft.height() > rect.height()
836             || topRight.height() + bottomRight.height() > rect.height()) {
837         // Not all the radii fit, return a rect. This matches the behavior of
838         // Path::createRoundedRectangle. Without this we attempt to draw a round
839         // shadow for a square box.
840         fillRect(rect, color, colorSpace);
841         return;
842     }
843
844     SkPath path;
845     addCornerArc(&path, r, topRight, 270);
846     addCornerArc(&path, r, bottomRight, 0);
847     addCornerArc(&path, r, bottomLeft, 90);
848     addCornerArc(&path, r, topLeft, 180);
849
850     SkPaint paint;
851     platformContext()->setupPaintForFilling(&paint);
852     paint.setColor(color.rgb());
853     platformContext()->canvas()->drawPath(path, paint);
854 }
855
856 AffineTransform GraphicsContext::getCTM() const
857 {
858     const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
859     return AffineTransform(SkScalarToDouble(m.getScaleX()),
860                            SkScalarToDouble(m.getSkewY()),
861                            SkScalarToDouble(m.getSkewX()),
862                            SkScalarToDouble(m.getScaleY()),
863                            SkScalarToDouble(m.getTranslateX()),
864                            SkScalarToDouble(m.getTranslateY()));
865 }
866
867 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode)
868 {
869     return rect;
870 }
871
872 void GraphicsContext::scale(const FloatSize& size)
873 {
874     if (paintingDisabled())
875         return;
876
877     platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
878         WebCoreFloatToSkScalar(size.height()));
879 }
880
881 void GraphicsContext::setAlpha(float alpha)
882 {
883     if (paintingDisabled())
884         return;
885
886     platformContext()->setAlpha(alpha);
887 }
888
889 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
890 {
891     if (paintingDisabled())
892         return;
893
894     platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
895 }
896
897 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
898 {
899     return platformContext()->interpolationQuality();
900 }
901
902 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality q)
903 {
904     platformContext()->setInterpolationQuality(q);
905 }
906
907 void GraphicsContext::setLineCap(LineCap cap)
908 {
909     if (paintingDisabled())
910         return;
911     switch (cap) {
912     case ButtCap:
913         platformContext()->setLineCap(SkPaint::kButt_Cap);
914         break;
915     case RoundCap:
916         platformContext()->setLineCap(SkPaint::kRound_Cap);
917         break;
918     case SquareCap:
919         platformContext()->setLineCap(SkPaint::kSquare_Cap);
920         break;
921     default:
922         ASSERT(0);
923         break;
924     }
925 }
926
927 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
928 {
929     if (paintingDisabled())
930         return;
931
932     // FIXME: This is lifted directly off SkiaSupport, lines 49-74
933     // so it is not guaranteed to work correctly.
934     size_t dashLength = dashes.size();
935     if (!dashLength) {
936         // If no dash is set, revert to solid stroke
937         // FIXME: do we need to set NoStroke in some cases?
938         platformContext()->setStrokeStyle(SolidStroke);
939         platformContext()->setDashPathEffect(0);
940         return;
941     }
942
943     size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
944     SkScalar* intervals = new SkScalar[count];
945
946     for (unsigned int i = 0; i < count; i++)
947         intervals[i] = dashes[i % dashLength];
948
949     platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
950
951     delete[] intervals;
952 }
953
954 void GraphicsContext::setLineJoin(LineJoin join)
955 {
956     if (paintingDisabled())
957         return;
958     switch (join) {
959     case MiterJoin:
960         platformContext()->setLineJoin(SkPaint::kMiter_Join);
961         break;
962     case RoundJoin:
963         platformContext()->setLineJoin(SkPaint::kRound_Join);
964         break;
965     case BevelJoin:
966         platformContext()->setLineJoin(SkPaint::kBevel_Join);
967         break;
968     default:
969         ASSERT(0);
970         break;
971     }
972 }
973
974 void GraphicsContext::setMiterLimit(float limit)
975 {
976     if (paintingDisabled())
977         return;
978     platformContext()->setMiterLimit(limit);
979 }
980
981 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
982 {
983     if (paintingDisabled())
984         return;
985
986     platformContext()->setFillColor(color.rgb());
987 }
988
989 void GraphicsContext::setPlatformShadow(const FloatSize& size,
990                                         float blurFloat,
991                                         const Color& color,
992                                         ColorSpace colorSpace)
993 {
994     if (paintingDisabled())
995         return;
996
997     // Detect when there's no effective shadow and clear the looper.
998     if (!size.width() && !size.height() && !blurFloat) {
999         platformContext()->setDrawLooper(0);
1000         return;
1001     }
1002
1003     double width = size.width();
1004     double height = size.height();
1005     double blur = blurFloat;
1006
1007     uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag;
1008     SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode;
1009
1010     if (m_state.shadowsIgnoreTransforms)  {
1011         // Currently only the GraphicsContext associated with the
1012         // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
1013         // Transforms. So with this flag set, we know this state is associated
1014         // with a CanvasRenderingContext.
1015         mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
1016
1017         // CSS wants us to ignore the original's alpha, but Canvas wants us to
1018         // modulate with it. Using shadowsIgnoreTransforms to tell us that we're
1019         // in a Canvas, we change the colormode to kDst_Mode, so we don't overwrite
1020         // it with our layer's (default opaque-black) color.
1021         colorMode = SkXfermode::kDst_Mode;
1022
1023         // CG uses natural orientation for Y axis, but the HTML5 canvas spec
1024         // does not.
1025         // So we now flip the height since it was flipped in
1026         // CanvasRenderingContext in order to work with CG.
1027         height = -height;
1028     }
1029
1030     SkColor c;
1031     if (color.isValid())
1032         c = color.rgb();
1033     else
1034         c = SkColorSetARGB(0xFF/3, 0, 0, 0);    // "std" apple shadow color.
1035
1036     // TODO(tc): Should we have a max value for the blur?  CG clamps at 1000.0
1037     // for perf reasons.
1038
1039     SkLayerDrawLooper* dl = new SkLayerDrawLooper;
1040     SkAutoUnref aur(dl);
1041
1042     // top layer, we just draw unchanged
1043     dl->addLayer();
1044
1045     // lower layer contains our offset, blur, and colorfilter
1046     SkLayerDrawLooper::LayerInfo info;
1047
1048     info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur
1049     info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
1050     info.fColorMode = colorMode;
1051     info.fOffset.set(width, height);
1052     info.fPostTranslate = m_state.shadowsIgnoreTransforms;
1053
1054     SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags);
1055
1056     SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode);
1057
1058     SkPaint* paint = dl->addLayer(info);
1059     SkSafeUnref(paint->setMaskFilter(mf));
1060     SkSafeUnref(paint->setColorFilter(cf));
1061
1062     // dl is now built, just install it
1063     platformContext()->setDrawLooper(dl);
1064 }
1065
1066 void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
1067 {
1068     if (paintingDisabled())
1069         return;
1070
1071     platformContext()->setStrokeColor(strokecolor.rgb());
1072 }
1073
1074 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle stroke)
1075 {
1076     if (paintingDisabled())
1077         return;
1078
1079     platformContext()->setStrokeStyle(stroke);
1080 }
1081
1082 void GraphicsContext::setPlatformStrokeThickness(float thickness)
1083 {
1084     if (paintingDisabled())
1085         return;
1086
1087     platformContext()->setStrokeThickness(thickness);
1088 }
1089
1090 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
1091 {
1092     if (paintingDisabled())
1093         return;
1094
1095     platformContext()->setTextDrawingMode(mode);
1096 }
1097
1098 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
1099 {
1100 }
1101
1102 void GraphicsContext::setPlatformShouldAntialias(bool enable)
1103 {
1104     if (paintingDisabled())
1105         return;
1106
1107     platformContext()->setUseAntialiasing(enable);
1108 }
1109
1110 void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
1111 {
1112     if (paintingDisabled())
1113         return;
1114
1115     platformContext()->makeGrContextCurrent();
1116
1117     SkPaint paint;
1118     SkRect oval = r;
1119     if (strokeStyle() == NoStroke) {
1120         // Stroke using the fill color.
1121         // TODO(brettw) is this really correct? It seems unreasonable.
1122         platformContext()->setupPaintForFilling(&paint);
1123         paint.setStyle(SkPaint::kStroke_Style);
1124         paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
1125     } else
1126         platformContext()->setupPaintForStroking(&paint, 0, 0);
1127
1128     // We do this before converting to scalar, so we don't overflow SkFixed.
1129     startAngle = fastMod(startAngle, 360);
1130     angleSpan = fastMod(angleSpan, 360);
1131
1132     SkPath path;
1133     path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
1134     if (!isPathSkiaSafe(getCTM(), path))
1135         return;
1136     platformContext()->canvas()->drawPath(path, paint);
1137 }
1138
1139 void GraphicsContext::strokePath(const Path& pathToStroke)
1140 {
1141     if (paintingDisabled())
1142         return;
1143
1144     SkPath path = *pathToStroke.platformPath();
1145     if (!isPathSkiaSafe(getCTM(), path))
1146         return;
1147
1148     platformContext()->makeGrContextCurrent();
1149
1150     SkPaint paint;
1151     platformContext()->setupPaintForStroking(&paint, 0, 0);
1152     platformContext()->canvas()->drawPath(path, paint);
1153 }
1154
1155 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
1156 {
1157     if (paintingDisabled())
1158         return;
1159
1160     if (!isRectSkiaSafe(getCTM(), rect))
1161         return;
1162
1163     platformContext()->makeGrContextCurrent();
1164
1165     SkPaint paint;
1166     platformContext()->setupPaintForStroking(&paint, 0, 0);
1167     paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
1168     // strokerect has special rules for CSS when the rect is degenerate:
1169     // if width==0 && height==0, do nothing
1170     // if width==0 || height==0, then just draw line for the other dimension
1171     SkRect r(rect);
1172     bool validW = r.width() > 0;
1173     bool validH = r.height() > 0;
1174     SkCanvas* canvas = platformContext()->canvas();
1175     if (validW && validH)
1176         canvas->drawRect(r, paint);
1177     else if (validW || validH) {
1178         // we are expected to respect the lineJoin, so we can't just call
1179         // drawLine -- we have to create a path that doubles back on itself.
1180         SkPath path;
1181         path.moveTo(r.fLeft, r.fTop);
1182         path.lineTo(r.fRight, r.fBottom);
1183         path.close();
1184         canvas->drawPath(path, paint);
1185     }
1186 }
1187
1188 void GraphicsContext::rotate(float angleInRadians)
1189 {
1190     if (paintingDisabled())
1191         return;
1192
1193     platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
1194         angleInRadians * (180.0f / 3.14159265f)));
1195 }
1196
1197 void GraphicsContext::translate(float w, float h)
1198 {
1199     if (paintingDisabled())
1200         return;
1201
1202     platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
1203                                            WebCoreFloatToSkScalar(h));
1204 }
1205
1206 void GraphicsContext::setGraphicsContext3D(GraphicsContext3D* context, DrawingBuffer* drawingBuffer, const IntSize& size)
1207 {
1208     platformContext()->setGraphicsContext3D(context, drawingBuffer, size);
1209 }
1210
1211 bool GraphicsContext::isAcceleratedContext() const
1212 {
1213     return platformContext()->isAccelerated();
1214 }
1215
1216 bool GraphicsContext::paintsIntoImageBuffer() const
1217 {
1218     return platformContext()->paintsIntoImageBuffer();
1219 }
1220
1221 #if PLATFORM(CHROMIUM) && OS(DARWIN)
1222 CGColorSpaceRef deviceRGBColorSpaceRef()
1223 {
1224     static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
1225     return deviceSpace;
1226 }
1227 #endif
1228
1229 }  // namespace WebCore