[SKIA] Must make skia's GL context current before drawing in GraphicsContext::clearRect
[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     platformContext()->makeGrContextCurrent();
300     SkPath path;
301     path.addOval(r, SkPath::kCW_Direction);
302     // only perform the inset if we won't invert r
303     if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
304         // Adding one to the thickness doesn't make the border too thick as
305         // it's painted over afterwards. But without this adjustment the
306         // border appears a little anemic after anti-aliasing.
307         r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
308         path.addOval(r, SkPath::kCCW_Direction);
309     }
310     platformContext()->clipPathAntiAliased(path);
311 }
312
313 void GraphicsContext::clearPlatformShadow()
314 {
315     if (paintingDisabled())
316         return;
317     platformContext()->setDrawLooper(0);
318 }
319
320 void GraphicsContext::clearRect(const FloatRect& rect)
321 {
322     if (paintingDisabled())
323         return;
324
325     SkRect r = rect;
326     if (!isRectSkiaSafe(getCTM(), r))
327         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
328
329     platformContext()->makeGrContextCurrent();
330
331     SkPaint paint;
332     platformContext()->setupPaintForFilling(&paint);
333     paint.setXfermodeMode(SkXfermode::kClear_Mode);
334     platformContext()->canvas()->drawRect(r, paint);
335 }
336
337 void GraphicsContext::clip(const FloatRect& rect)
338 {
339     if (paintingDisabled())
340         return;
341
342     SkRect r(rect);
343     if (!isRectSkiaSafe(getCTM(), r))
344         return;
345
346     platformContext()->makeGrContextCurrent();
347     platformContext()->canvas()->clipRect(r);
348 }
349
350 void GraphicsContext::clip(const Path& path)
351 {
352     if (paintingDisabled())
353         return;
354
355     const SkPath& p = *path.platformPath();
356     if (!isPathSkiaSafe(getCTM(), p))
357         return;
358
359     platformContext()->makeGrContextCurrent();
360     platformContext()->clipPathAntiAliased(p);
361 }
362
363 void GraphicsContext::canvasClip(const Path& path)
364 {
365     if (paintingDisabled())
366         return;
367
368     const SkPath& p = *path.platformPath();
369     if (!isPathSkiaSafe(getCTM(), p))
370         return;
371
372     platformContext()->canvasClipPath(p);
373 }
374
375 void GraphicsContext::clipOut(const IntRect& rect)
376 {
377     if (paintingDisabled())
378         return;
379
380     SkRect r(rect);
381     if (!isRectSkiaSafe(getCTM(), r))
382         return;
383
384     platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
385 }
386
387 void GraphicsContext::clipOut(const Path& p)
388 {
389     if (paintingDisabled())
390         return;
391
392     const SkPath& path = *p.platformPath();
393     if (!isPathSkiaSafe(getCTM(), path))
394         return;
395
396     platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
397 }
398
399 void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule)
400 {
401     if (paintingDisabled())
402         return;
403
404     SkPath path = *pathToClip.platformPath();
405     if (!isPathSkiaSafe(getCTM(), path))
406         return;
407
408     path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
409     platformContext()->clipPathAntiAliased(path);
410 }
411
412 void GraphicsContext::concatCTM(const AffineTransform& affine)
413 {
414     if (paintingDisabled())
415         return;
416
417     platformContext()->canvas()->concat(affine);
418 }
419
420 void GraphicsContext::setCTM(const AffineTransform& affine)
421 {
422     if (paintingDisabled())
423         return;
424
425     platformContext()->canvas()->setMatrix(affine);
426 }
427
428 static void setPathFromConvexPoints(SkPath* path, size_t numPoints, const FloatPoint* points)
429 {
430     path->incReserve(numPoints);
431     path->moveTo(WebCoreFloatToSkScalar(points[0].x()),
432                  WebCoreFloatToSkScalar(points[0].y()));
433     for (size_t i = 1; i < numPoints; ++i) {
434         path->lineTo(WebCoreFloatToSkScalar(points[i].x()),
435                      WebCoreFloatToSkScalar(points[i].y()));
436     }
437     path->setIsConvex(true);
438 }
439
440 void GraphicsContext::drawConvexPolygon(size_t numPoints,
441                                         const FloatPoint* points,
442                                         bool shouldAntialias)
443 {
444     if (paintingDisabled())
445         return;
446
447     if (numPoints <= 1)
448         return;
449
450     platformContext()->makeGrContextCurrent();
451
452     SkPath path;
453     setPathFromConvexPoints(&path, numPoints, points);
454
455     if (!isPathSkiaSafe(getCTM(), path))
456         return;
457
458     SkPaint paint;
459     platformContext()->setupPaintForFilling(&paint);
460     paint.setAntiAlias(shouldAntialias);
461     platformContext()->canvas()->drawPath(path, paint);
462
463     if (strokeStyle() != NoStroke) {
464         paint.reset();
465         platformContext()->setupPaintForStroking(&paint, 0, 0);
466         platformContext()->canvas()->drawPath(path, paint);
467     }
468 }
469
470 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
471 {
472     if (paintingDisabled())
473         return;
474
475     if (numPoints <= 1)
476         return;
477
478     SkPath path;
479     setPathFromConvexPoints(&path, numPoints, points);
480     platformContext()->canvas()->clipPath(path);
481 }
482
483 // This method is only used to draw the little circles used in lists.
484 void GraphicsContext::drawEllipse(const IntRect& elipseRect)
485 {
486     if (paintingDisabled())
487         return;
488
489     SkRect rect = elipseRect;
490     if (!isRectSkiaSafe(getCTM(), rect))
491         return;
492
493     platformContext()->makeGrContextCurrent();
494     SkPaint paint;
495     platformContext()->setupPaintForFilling(&paint);
496     platformContext()->canvas()->drawOval(rect, paint);
497
498     if (strokeStyle() != NoStroke) {
499         paint.reset();
500         platformContext()->setupPaintForStroking(&paint, &rect, 0);
501         platformContext()->canvas()->drawOval(rect, paint);
502     }
503 }
504
505 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
506 {
507     // FIXME: implement
508 }
509
510 static inline void drawOuterPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width)
511 {
512 #if PLATFORM(CHROMIUM) && OS(DARWIN)
513     paint.setAlpha(64);
514     paint.setStrokeWidth(width);
515     paint.setPathEffect(new SkCornerPathEffect((width - 1) * 0.5f))->unref();
516 #else
517     paint.setStrokeWidth(1);
518     paint.setPathEffect(new SkCornerPathEffect(1))->unref();
519 #endif
520     canvas->drawPath(path, paint);
521 }
522
523 static inline void drawInnerPath(SkCanvas* canvas, const SkPath& path, SkPaint& paint, int width)
524 {
525 #if PLATFORM(CHROMIUM) && OS(DARWIN)
526     paint.setAlpha(128);
527     paint.setStrokeWidth(width * 0.5f);
528     canvas->drawPath(path, paint);
529 #endif
530 }
531
532 static inline SkScalar getFocusRingOutset(int width)
533 {
534 #if PLATFORM(CHROMIUM) && OS(DARWIN)
535     return (width * 0.5f) + 0.25f;
536 #else
537     return 0.5f;
538 #endif
539 }
540
541 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color)
542 {
543     if (paintingDisabled())
544         return;
545
546     unsigned rectCount = rects.size();
547     if (!rectCount)
548         return;
549
550     platformContext()->makeGrContextCurrent();
551     SkRegion focusRingRegion;
552     const SkScalar focusRingOutset = getFocusRingOutset(width);
553     for (unsigned i = 0; i < rectCount; i++) {
554         SkIRect r = rects[i];
555         r.inset(-focusRingOutset, -focusRingOutset);
556         focusRingRegion.op(r, SkRegion::kUnion_Op);
557     }
558
559     SkPath path;
560     SkPaint paint;
561     paint.setAntiAlias(true);
562     paint.setStyle(SkPaint::kStroke_Style);
563
564     paint.setColor(color.rgb());
565     focusRingRegion.getBoundaryPath(&path);
566     SkCanvas* canvas = platformContext()->canvas();
567     drawOuterPath(canvas, path, paint, width);
568     drawInnerPath(canvas, path, paint, width);
569 }
570
571 // This is only used to draw borders.
572 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
573 {
574     if (paintingDisabled())
575         return;
576
577     StrokeStyle penStyle = strokeStyle();
578     if (penStyle == NoStroke)
579         return;
580
581     SkPaint paint;
582     if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
583         return;
584
585     platformContext()->makeGrContextCurrent();
586
587     FloatPoint p1 = point1;
588     FloatPoint p2 = point2;
589     bool isVerticalLine = (p1.x() == p2.x());
590     int width = roundf(strokeThickness());
591
592     // We know these are vertical or horizontal lines, so the length will just
593     // be the sum of the displacement component vectors give or take 1 -
594     // probably worth the speed up of no square root, which also won't be exact.
595     FloatSize disp = p2 - p1;
596     int length = SkScalarRound(disp.width() + disp.height());
597     platformContext()->setupPaintForStroking(&paint, 0, length);
598
599     if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
600         // Do a rect fill of our endpoints.  This ensures we always have the
601         // appearance of being a border.  We then draw the actual dotted/dashed line.
602
603         SkRect r1, r2;
604         r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
605         r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);
606
607         if (isVerticalLine) {
608             r1.offset(-width / 2, 0);
609             r2.offset(-width / 2, -width);
610         } else {
611             r1.offset(0, -width / 2);
612             r2.offset(-width, -width / 2);
613         }
614         SkPaint fillPaint;
615         fillPaint.setColor(paint.getColor());
616         platformContext()->canvas()->drawRect(r1, fillPaint);
617         platformContext()->canvas()->drawRect(r2, fillPaint);
618     }
619
620     adjustLineToPixelBoundaries(p1, p2, width, penStyle);
621     SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };
622
623     platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
624 }
625
626 void GraphicsContext::drawLineForTextChecking(const FloatPoint& pt, float width, TextCheckingLineStyle style)
627 {
628     if (paintingDisabled())
629         return;
630
631     platformContext()->makeGrContextCurrent();
632
633     // Create the pattern we'll use to draw the underline.
634     static SkBitmap* misspellBitmap = 0;
635     if (!misspellBitmap) {
636         // We use a 2-pixel-high misspelling indicator because that seems to be
637         // what WebKit is designed for, and how much room there is in a typical
638         // page for it.
639         const int rowPixels = 32;  // Must be multiple of 4 for pattern below.
640         const int colPixels = 2;
641         misspellBitmap = new SkBitmap;
642         misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
643                                    rowPixels, colPixels);
644         misspellBitmap->allocPixels();
645
646         misspellBitmap->eraseARGB(0, 0, 0, 0);
647         const uint32_t lineColor = 0xFFFF0000;  // Opaque red.
648         const uint32_t antiColor = 0x60600000;  // Semitransparent red.
649
650         // Pattern:  X o   o X o   o X
651         //             o X o   o X o
652         uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
653         uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
654         for (int x = 0; x < rowPixels; x++) {
655             switch (x % 4) {
656             case 0:
657                 row1[x] = lineColor;
658                 break;
659             case 1:
660                 row1[x] = antiColor;
661                 row2[x] = antiColor;
662                 break;
663             case 2:
664                 row2[x] = lineColor;
665                 break;
666             case 3:
667                 row1[x] = antiColor;
668                 row2[x] = antiColor;
669                 break;
670             }
671         }
672     }
673
674     // Offset it vertically by 1 so that there's some space under the text.
675     SkScalar originX = WebCoreFloatToSkScalar(pt.x());
676     SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1;
677
678     // Make a shader for the bitmap with an origin of the box we'll draw. This
679     // shader is refcounted and will have an initial refcount of 1.
680     SkShader* shader = SkShader::CreateBitmapShader(
681         *misspellBitmap, SkShader::kRepeat_TileMode,
682         SkShader::kRepeat_TileMode);
683     SkMatrix matrix;
684     matrix.reset();
685     matrix.postTranslate(originX, originY);
686     shader->setLocalMatrix(matrix);
687
688     // Assign the shader to the paint & release our reference. The paint will
689     // now own the shader and the shader will be destroyed when the paint goes
690     // out of scope.
691     SkPaint paint;
692     paint.setShader(shader);
693     shader->unref();
694
695     SkRect rect;
696     rect.set(originX,
697              originY,
698              originX + WebCoreFloatToSkScalar(width),
699              originY + SkIntToScalar(misspellBitmap->height()));
700     platformContext()->canvas()->drawRect(rect, paint);
701 }
702
703 void GraphicsContext::drawLineForText(const FloatPoint& pt,
704                                       float width,
705                                       bool printing)
706 {
707     if (paintingDisabled())
708         return;
709
710     if (width <= 0)
711         return;
712
713     platformContext()->makeGrContextCurrent();
714
715     int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
716     SkRect r;
717     r.fLeft = WebCoreFloatToSkScalar(pt.x());
718     r.fTop = WebCoreFloatToSkScalar(pt.y());
719     r.fRight = r.fLeft + WebCoreFloatToSkScalar(width);
720     r.fBottom = r.fTop + SkIntToScalar(thickness);
721
722     SkPaint paint;
723     platformContext()->setupPaintForFilling(&paint);
724     // Text lines are drawn using the stroke color.
725     paint.setColor(platformContext()->effectiveStrokeColor());
726     platformContext()->canvas()->drawRect(r, paint);
727 }
728
729 // Draws a filled rectangle with a stroked border.
730 void GraphicsContext::drawRect(const IntRect& rect)
731 {
732     if (paintingDisabled())
733         return;
734
735     platformContext()->makeGrContextCurrent();
736
737     SkRect r = rect;
738     if (!isRectSkiaSafe(getCTM(), r)) {
739         // See the fillRect below.
740         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
741     }
742
743     platformContext()->drawRect(r);
744 }
745
746 void GraphicsContext::fillPath(const Path& pathToFill)
747 {
748     if (paintingDisabled())
749         return;
750
751     SkPath path = *pathToFill.platformPath();
752     if (!isPathSkiaSafe(getCTM(), path))
753       return;
754
755     platformContext()->makeGrContextCurrent();
756
757     const GraphicsContextState& state = m_state;
758     path.setFillType(state.fillRule == RULE_EVENODD ?
759         SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
760
761     SkPaint paint;
762     platformContext()->setupPaintForFilling(&paint);
763
764     platformContext()->canvas()->drawPath(path, paint);
765 }
766
767 void GraphicsContext::fillRect(const FloatRect& rect)
768 {
769     if (paintingDisabled())
770         return;
771
772     SkRect r = rect;
773     if (!isRectSkiaSafe(getCTM(), r)) {
774         // See the other version of fillRect below.
775         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
776     }
777
778     platformContext()->save();
779
780     platformContext()->makeGrContextCurrent();
781
782     SkPaint paint;
783     platformContext()->setupPaintForFilling(&paint);
784     platformContext()->canvas()->drawRect(r, paint);
785
786     platformContext()->restore();
787 }
788
789 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
790 {
791     if (paintingDisabled())
792         return;
793
794     platformContext()->makeGrContextCurrent();
795
796     SkRect r = rect;
797     if (!isRectSkiaSafe(getCTM(), r)) {
798         // Special case when the rectangle overflows fixed point. This is a
799         // workaround to fix bug 1212844. When the input rectangle is very
800         // large, it can overflow Skia's internal fixed point rect. This
801         // should be fixable in Skia (since the output bitmap isn't that
802         // large), but until that is fixed, we try to handle it ourselves.
803         //
804         // We manually clip the rectangle to the current clip rect. This
805         // will prevent overflow. The rectangle will be transformed to the
806         // canvas' coordinate space before it is converted to fixed point
807         // so we are guaranteed not to overflow after doing this.
808         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
809     }
810
811     SkPaint paint;
812     platformContext()->setupPaintCommon(&paint);
813     paint.setColor(color.rgb());
814     platformContext()->canvas()->drawRect(r, paint);
815 }
816
817 void GraphicsContext::fillRoundedRect(const IntRect& rect,
818                                       const IntSize& topLeft,
819                                       const IntSize& topRight,
820                                       const IntSize& bottomLeft,
821                                       const IntSize& bottomRight,
822                                       const Color& color,
823                                       ColorSpace colorSpace)
824 {
825     if (paintingDisabled())
826         return;
827
828     platformContext()->makeGrContextCurrent();
829
830     SkRect r = rect;
831     if (!isRectSkiaSafe(getCTM(), r))
832         // See fillRect().
833         ClipRectToCanvas(*platformContext()->canvas(), r, &r);
834
835     if (topLeft.width() + topRight.width() > rect.width()
836             || bottomLeft.width() + bottomRight.width() > rect.width()
837             || topLeft.height() + bottomLeft.height() > rect.height()
838             || topRight.height() + bottomRight.height() > rect.height()) {
839         // Not all the radii fit, return a rect. This matches the behavior of
840         // Path::createRoundedRectangle. Without this we attempt to draw a round
841         // shadow for a square box.
842         fillRect(rect, color, colorSpace);
843         return;
844     }
845
846     SkPath path;
847     addCornerArc(&path, r, topRight, 270);
848     addCornerArc(&path, r, bottomRight, 0);
849     addCornerArc(&path, r, bottomLeft, 90);
850     addCornerArc(&path, r, topLeft, 180);
851
852     SkPaint paint;
853     platformContext()->setupPaintForFilling(&paint);
854     paint.setColor(color.rgb());
855     platformContext()->canvas()->drawPath(path, paint);
856 }
857
858 AffineTransform GraphicsContext::getCTM() const
859 {
860     const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
861     return AffineTransform(SkScalarToDouble(m.getScaleX()),
862                            SkScalarToDouble(m.getSkewY()),
863                            SkScalarToDouble(m.getSkewX()),
864                            SkScalarToDouble(m.getScaleY()),
865                            SkScalarToDouble(m.getTranslateX()),
866                            SkScalarToDouble(m.getTranslateY()));
867 }
868
869 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode)
870 {
871     return rect;
872 }
873
874 void GraphicsContext::scale(const FloatSize& size)
875 {
876     if (paintingDisabled())
877         return;
878
879     platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
880         WebCoreFloatToSkScalar(size.height()));
881 }
882
883 void GraphicsContext::setAlpha(float alpha)
884 {
885     if (paintingDisabled())
886         return;
887
888     platformContext()->setAlpha(alpha);
889 }
890
891 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
892 {
893     if (paintingDisabled())
894         return;
895
896     platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
897 }
898
899 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
900 {
901     return platformContext()->interpolationQuality();
902 }
903
904 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality q)
905 {
906     platformContext()->setInterpolationQuality(q);
907 }
908
909 void GraphicsContext::setLineCap(LineCap cap)
910 {
911     if (paintingDisabled())
912         return;
913     switch (cap) {
914     case ButtCap:
915         platformContext()->setLineCap(SkPaint::kButt_Cap);
916         break;
917     case RoundCap:
918         platformContext()->setLineCap(SkPaint::kRound_Cap);
919         break;
920     case SquareCap:
921         platformContext()->setLineCap(SkPaint::kSquare_Cap);
922         break;
923     default:
924         ASSERT(0);
925         break;
926     }
927 }
928
929 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
930 {
931     if (paintingDisabled())
932         return;
933
934     // FIXME: This is lifted directly off SkiaSupport, lines 49-74
935     // so it is not guaranteed to work correctly.
936     size_t dashLength = dashes.size();
937     if (!dashLength) {
938         // If no dash is set, revert to solid stroke
939         // FIXME: do we need to set NoStroke in some cases?
940         platformContext()->setStrokeStyle(SolidStroke);
941         platformContext()->setDashPathEffect(0);
942         return;
943     }
944
945     size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
946     SkScalar* intervals = new SkScalar[count];
947
948     for (unsigned int i = 0; i < count; i++)
949         intervals[i] = dashes[i % dashLength];
950
951     platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
952
953     delete[] intervals;
954 }
955
956 void GraphicsContext::setLineJoin(LineJoin join)
957 {
958     if (paintingDisabled())
959         return;
960     switch (join) {
961     case MiterJoin:
962         platformContext()->setLineJoin(SkPaint::kMiter_Join);
963         break;
964     case RoundJoin:
965         platformContext()->setLineJoin(SkPaint::kRound_Join);
966         break;
967     case BevelJoin:
968         platformContext()->setLineJoin(SkPaint::kBevel_Join);
969         break;
970     default:
971         ASSERT(0);
972         break;
973     }
974 }
975
976 void GraphicsContext::setMiterLimit(float limit)
977 {
978     if (paintingDisabled())
979         return;
980     platformContext()->setMiterLimit(limit);
981 }
982
983 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
984 {
985     if (paintingDisabled())
986         return;
987
988     platformContext()->setFillColor(color.rgb());
989 }
990
991 void GraphicsContext::setPlatformShadow(const FloatSize& size,
992                                         float blurFloat,
993                                         const Color& color,
994                                         ColorSpace colorSpace)
995 {
996     if (paintingDisabled())
997         return;
998
999     // Detect when there's no effective shadow and clear the looper.
1000     if (!size.width() && !size.height() && !blurFloat) {
1001         platformContext()->setDrawLooper(0);
1002         return;
1003     }
1004
1005     double width = size.width();
1006     double height = size.height();
1007     double blur = blurFloat;
1008
1009     uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag;
1010     SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode;
1011
1012     if (m_state.shadowsIgnoreTransforms)  {
1013         // Currently only the GraphicsContext associated with the
1014         // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
1015         // Transforms. So with this flag set, we know this state is associated
1016         // with a CanvasRenderingContext.
1017         mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
1018
1019         // CSS wants us to ignore the original's alpha, but Canvas wants us to
1020         // modulate with it. Using shadowsIgnoreTransforms to tell us that we're
1021         // in a Canvas, we change the colormode to kDst_Mode, so we don't overwrite
1022         // it with our layer's (default opaque-black) color.
1023         colorMode = SkXfermode::kDst_Mode;
1024
1025         // CG uses natural orientation for Y axis, but the HTML5 canvas spec
1026         // does not.
1027         // So we now flip the height since it was flipped in
1028         // CanvasRenderingContext in order to work with CG.
1029         height = -height;
1030     }
1031
1032     SkColor c;
1033     if (color.isValid())
1034         c = color.rgb();
1035     else
1036         c = SkColorSetARGB(0xFF/3, 0, 0, 0);    // "std" apple shadow color.
1037
1038     // TODO(tc): Should we have a max value for the blur?  CG clamps at 1000.0
1039     // for perf reasons.
1040
1041     SkLayerDrawLooper* dl = new SkLayerDrawLooper;
1042     SkAutoUnref aur(dl);
1043
1044     // top layer, we just draw unchanged
1045     dl->addLayer();
1046
1047     // lower layer contains our offset, blur, and colorfilter
1048     SkLayerDrawLooper::LayerInfo info;
1049
1050     info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur
1051     info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
1052     info.fColorMode = colorMode;
1053     info.fOffset.set(width, height);
1054     info.fPostTranslate = m_state.shadowsIgnoreTransforms;
1055
1056     SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags);
1057
1058     SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode);
1059
1060     SkPaint* paint = dl->addLayer(info);
1061     SkSafeUnref(paint->setMaskFilter(mf));
1062     SkSafeUnref(paint->setColorFilter(cf));
1063
1064     // dl is now built, just install it
1065     platformContext()->setDrawLooper(dl);
1066 }
1067
1068 void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace)
1069 {
1070     if (paintingDisabled())
1071         return;
1072
1073     platformContext()->setStrokeColor(strokecolor.rgb());
1074 }
1075
1076 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle stroke)
1077 {
1078     if (paintingDisabled())
1079         return;
1080
1081     platformContext()->setStrokeStyle(stroke);
1082 }
1083
1084 void GraphicsContext::setPlatformStrokeThickness(float thickness)
1085 {
1086     if (paintingDisabled())
1087         return;
1088
1089     platformContext()->setStrokeThickness(thickness);
1090 }
1091
1092 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
1093 {
1094     if (paintingDisabled())
1095         return;
1096
1097     platformContext()->setTextDrawingMode(mode);
1098 }
1099
1100 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
1101 {
1102 }
1103
1104 void GraphicsContext::setPlatformShouldAntialias(bool enable)
1105 {
1106     if (paintingDisabled())
1107         return;
1108
1109     platformContext()->setUseAntialiasing(enable);
1110 }
1111
1112 void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
1113 {
1114     if (paintingDisabled())
1115         return;
1116
1117     platformContext()->makeGrContextCurrent();
1118
1119     SkPaint paint;
1120     SkRect oval = r;
1121     if (strokeStyle() == NoStroke) {
1122         // Stroke using the fill color.
1123         // TODO(brettw) is this really correct? It seems unreasonable.
1124         platformContext()->setupPaintForFilling(&paint);
1125         paint.setStyle(SkPaint::kStroke_Style);
1126         paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
1127     } else
1128         platformContext()->setupPaintForStroking(&paint, 0, 0);
1129
1130     // We do this before converting to scalar, so we don't overflow SkFixed.
1131     startAngle = fastMod(startAngle, 360);
1132     angleSpan = fastMod(angleSpan, 360);
1133
1134     SkPath path;
1135     path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
1136     if (!isPathSkiaSafe(getCTM(), path))
1137         return;
1138     platformContext()->canvas()->drawPath(path, paint);
1139 }
1140
1141 void GraphicsContext::strokePath(const Path& pathToStroke)
1142 {
1143     if (paintingDisabled())
1144         return;
1145
1146     SkPath path = *pathToStroke.platformPath();
1147     if (!isPathSkiaSafe(getCTM(), path))
1148         return;
1149
1150     platformContext()->makeGrContextCurrent();
1151
1152     SkPaint paint;
1153     platformContext()->setupPaintForStroking(&paint, 0, 0);
1154     platformContext()->canvas()->drawPath(path, paint);
1155 }
1156
1157 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
1158 {
1159     if (paintingDisabled())
1160         return;
1161
1162     if (!isRectSkiaSafe(getCTM(), rect))
1163         return;
1164
1165     platformContext()->makeGrContextCurrent();
1166
1167     SkPaint paint;
1168     platformContext()->setupPaintForStroking(&paint, 0, 0);
1169     paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
1170     // strokerect has special rules for CSS when the rect is degenerate:
1171     // if width==0 && height==0, do nothing
1172     // if width==0 || height==0, then just draw line for the other dimension
1173     SkRect r(rect);
1174     bool validW = r.width() > 0;
1175     bool validH = r.height() > 0;
1176     SkCanvas* canvas = platformContext()->canvas();
1177     if (validW && validH)
1178         canvas->drawRect(r, paint);
1179     else if (validW || validH) {
1180         // we are expected to respect the lineJoin, so we can't just call
1181         // drawLine -- we have to create a path that doubles back on itself.
1182         SkPath path;
1183         path.moveTo(r.fLeft, r.fTop);
1184         path.lineTo(r.fRight, r.fBottom);
1185         path.close();
1186         canvas->drawPath(path, paint);
1187     }
1188 }
1189
1190 void GraphicsContext::rotate(float angleInRadians)
1191 {
1192     if (paintingDisabled())
1193         return;
1194
1195     platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
1196         angleInRadians * (180.0f / 3.14159265f)));
1197 }
1198
1199 void GraphicsContext::translate(float w, float h)
1200 {
1201     if (paintingDisabled())
1202         return;
1203
1204     platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
1205                                            WebCoreFloatToSkScalar(h));
1206 }
1207
1208 void GraphicsContext::setGraphicsContext3D(GraphicsContext3D* context, DrawingBuffer* framebuffer, const IntSize& size)
1209 {
1210     platformContext()->setGraphicsContext3D(context, framebuffer, size);
1211 }
1212
1213 #if PLATFORM(CHROMIUM) && OS(DARWIN)
1214 CGColorSpaceRef deviceRGBColorSpaceRef()
1215 {
1216     static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
1217     return deviceSpace;
1218 }
1219 #endif
1220
1221 }  // namespace WebCore