• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define LOG_TAG "PlatformGraphicsContextSkia"
2 #define LOG_NDEBUG 1
3 
4 #include "config.h"
5 #include "PlatformGraphicsContextSkia.h"
6 
7 #include "AndroidLog.h"
8 #include "Font.h"
9 #include "GraphicsContext.h"
10 #include "SkCanvas.h"
11 #include "SkCornerPathEffect.h"
12 #include "SkPaint.h"
13 #include "SkShader.h"
14 #include "SkiaUtils.h"
15 
16 namespace WebCore {
17 
18 // These are the flags we need when we call saveLayer for transparency.
19 // Since it does not appear that webkit intends this to also save/restore
20 // the matrix or clip, I do not give those flags (for performance)
21 #define TRANSPARENCY_SAVEFLAGS                                  \
22     (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag |   \
23                           SkCanvas::kFullColorLayer_SaveFlag)
24 
25 //**************************************
26 // Helper functions
27 //**************************************
28 
setrectForUnderline(SkRect * r,float lineThickness,const FloatPoint & point,int yOffset,float width)29 static void setrectForUnderline(SkRect* r, float lineThickness,
30                                 const FloatPoint& point, int yOffset, float width)
31 {
32 #if 0
33     if (lineThickness < 1) // Do we really need/want this?
34         lineThickness = 1;
35 #endif
36     r->fLeft    = point.x();
37     r->fTop     = point.y() + yOffset;
38     r->fRight   = r->fLeft + width;
39     r->fBottom  = r->fTop + lineThickness;
40 }
41 
fastMod(int value,int max)42 static inline int fastMod(int value, int max)
43 {
44     int sign = SkExtractSign(value);
45 
46     value = SkApplySign(value, sign);
47     if (value >= max)
48         value %= max;
49     return SkApplySign(value, sign);
50 }
51 
fixPaintForBitmapsThatMaySeam(SkPaint * paint)52 static inline void fixPaintForBitmapsThatMaySeam(SkPaint* paint) {
53     /*  Bitmaps may be drawn to seem next to other images. If we are drawn
54         zoomed, or at fractional coordinates, we may see cracks/edges if
55         we antialias, because that will cause us to draw the same pixels
56         more than once (e.g. from the left and right bitmaps that share
57         an edge).
58 
59         Disabling antialiasing fixes this, and since so far we are never
60         rotated at non-multiple-of-90 angles, this seems to do no harm
61      */
62     paint->setAntiAlias(false);
63 }
64 
65 //**************************************
66 // PlatformGraphicsContextSkia
67 //**************************************
68 
PlatformGraphicsContextSkia(SkCanvas * canvas,bool takeCanvasOwnership)69 PlatformGraphicsContextSkia::PlatformGraphicsContextSkia(SkCanvas* canvas,
70                                                          bool takeCanvasOwnership)
71     : PlatformGraphicsContext()
72     , mCanvas(canvas)
73     , m_deleteCanvas(takeCanvasOwnership)
74 {
75     m_gc = 0;
76 }
77 
~PlatformGraphicsContextSkia()78 PlatformGraphicsContextSkia::~PlatformGraphicsContextSkia()
79 {
80     if (m_deleteCanvas)
81         delete mCanvas;
82 }
83 
isPaintingDisabled()84 bool PlatformGraphicsContextSkia::isPaintingDisabled()
85 {
86     return !mCanvas;
87 }
88 
89 //**************************************
90 // State management
91 //**************************************
92 
beginTransparencyLayer(float opacity)93 void PlatformGraphicsContextSkia::beginTransparencyLayer(float opacity)
94 {
95     SkCanvas* canvas = mCanvas;
96     canvas->saveLayerAlpha(0, (int)(opacity * 255), TRANSPARENCY_SAVEFLAGS);
97 }
98 
endTransparencyLayer()99 void PlatformGraphicsContextSkia::endTransparencyLayer()
100 {
101     if (!mCanvas)
102         return;
103     mCanvas->restore();
104 }
105 
save()106 void PlatformGraphicsContextSkia::save()
107 {
108     PlatformGraphicsContext::save();
109     // Save our native canvas.
110     mCanvas->save();
111 }
112 
restore()113 void PlatformGraphicsContextSkia::restore()
114 {
115     PlatformGraphicsContext::restore();
116     // Restore our native canvas.
117     mCanvas->restore();
118 }
119 
120 //**************************************
121 // Matrix operations
122 //**************************************
123 
concatCTM(const AffineTransform & affine)124 void PlatformGraphicsContextSkia::concatCTM(const AffineTransform& affine)
125 {
126     mCanvas->concat(affine);
127 }
128 
rotate(float angleInRadians)129 void PlatformGraphicsContextSkia::rotate(float angleInRadians)
130 {
131     float value = angleInRadians * (180.0f / 3.14159265f);
132     mCanvas->rotate(SkFloatToScalar(value));
133 }
134 
scale(const FloatSize & size)135 void PlatformGraphicsContextSkia::scale(const FloatSize& size)
136 {
137     mCanvas->scale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
138 }
139 
translate(float x,float y)140 void PlatformGraphicsContextSkia::translate(float x, float y)
141 {
142     mCanvas->translate(SkFloatToScalar(x), SkFloatToScalar(y));
143 }
144 
getTotalMatrix()145 const SkMatrix& PlatformGraphicsContextSkia::getTotalMatrix()
146 {
147     return mCanvas->getTotalMatrix();
148 }
149 
150 //**************************************
151 // Clipping
152 //**************************************
153 
addInnerRoundedRectClip(const IntRect & rect,int thickness)154 void PlatformGraphicsContextSkia::addInnerRoundedRectClip(const IntRect& rect,
155                                                       int thickness)
156 {
157     SkPath path;
158     SkRect r(rect);
159 
160     path.addOval(r, SkPath::kCW_Direction);
161     // Only perform the inset if we won't invert r
162     if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
163         // Adding one to the thickness doesn't make the border too thick as
164         // it's painted over afterwards. But without this adjustment the
165         // border appears a little anemic after anti-aliasing.
166         r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1));
167         path.addOval(r, SkPath::kCCW_Direction);
168     }
169     mCanvas->clipPath(path, SkRegion::kIntersect_Op, true);
170 }
171 
canvasClip(const Path & path)172 void PlatformGraphicsContextSkia::canvasClip(const Path& path)
173 {
174     clip(path);
175 }
176 
clip(const FloatRect & rect)177 void PlatformGraphicsContextSkia::clip(const FloatRect& rect)
178 {
179     mCanvas->clipRect(rect);
180 }
181 
clip(const Path & path)182 void PlatformGraphicsContextSkia::clip(const Path& path)
183 {
184     mCanvas->clipPath(*path.platformPath(), SkRegion::kIntersect_Op, true);
185 }
186 
clipConvexPolygon(size_t numPoints,const FloatPoint *,bool antialias)187 void PlatformGraphicsContextSkia::clipConvexPolygon(size_t numPoints,
188                                                 const FloatPoint*, bool antialias)
189 {
190     if (numPoints <= 1)
191         return;
192 
193     // This is only used if HAVE_PATH_BASED_BORDER_RADIUS_DRAWING is defined
194     // in RenderObject.h which it isn't for us. TODO: Support that :)
195 }
196 
clipOut(const IntRect & r)197 void PlatformGraphicsContextSkia::clipOut(const IntRect& r)
198 {
199     mCanvas->clipRect(r, SkRegion::kDifference_Op);
200 }
201 
clipOut(const Path & path)202 void PlatformGraphicsContextSkia::clipOut(const Path& path)
203 {
204     mCanvas->clipPath(*path.platformPath(), SkRegion::kDifference_Op);
205 }
206 
clipPath(const Path & pathToClip,WindRule clipRule)207 void PlatformGraphicsContextSkia::clipPath(const Path& pathToClip, WindRule clipRule)
208 {
209     SkPath path = *pathToClip.platformPath();
210     path.setFillType(clipRule == RULE_EVENODD
211             ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
212     mCanvas->clipPath(path);
213 }
clearRect(const FloatRect & rect)214 void PlatformGraphicsContextSkia::clearRect(const FloatRect& rect)
215 {
216     SkPaint paint;
217 
218     setupPaintFill(&paint);
219     paint.setXfermodeMode(SkXfermode::kClear_Mode);
220 
221     mCanvas->drawRect(rect, paint);
222 }
223 
224 //**************************************
225 // Drawing
226 //**************************************
227 
drawBitmapPattern(const SkBitmap & bitmap,const SkMatrix & matrix,CompositeOperator compositeOp,const FloatRect & destRect)228 void PlatformGraphicsContextSkia::drawBitmapPattern(
229         const SkBitmap& bitmap, const SkMatrix& matrix,
230         CompositeOperator compositeOp, const FloatRect& destRect)
231 {
232     SkShader* shader = SkShader::CreateBitmapShader(bitmap,
233                                                     SkShader::kRepeat_TileMode,
234                                                     SkShader::kRepeat_TileMode);
235     shader->setLocalMatrix(matrix);
236     SkPaint paint;
237     setupPaintCommon(&paint);
238     paint.setAlpha(getNormalizedAlpha());
239     paint.setShader(shader);
240     paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
241     fixPaintForBitmapsThatMaySeam(&paint);
242     mCanvas->drawRect(destRect, paint);
243 }
244 
drawBitmapRect(const SkBitmap & bitmap,const SkIRect * src,const SkRect & dst,CompositeOperator op)245 void PlatformGraphicsContextSkia::drawBitmapRect(const SkBitmap& bitmap,
246                                              const SkIRect* src, const SkRect& dst,
247                                              CompositeOperator op)
248 {
249     SkPaint paint;
250     setupPaintCommon(&paint);
251     paint.setAlpha(getNormalizedAlpha());
252     paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
253     fixPaintForBitmapsThatMaySeam(&paint);
254 
255     mCanvas->drawBitmapRect(bitmap, src, dst, &paint);
256 }
257 
drawConvexPolygon(size_t numPoints,const FloatPoint * points,bool shouldAntialias)258 void PlatformGraphicsContextSkia::drawConvexPolygon(size_t numPoints,
259                                                 const FloatPoint* points,
260                                                 bool shouldAntialias)
261 {
262     if (numPoints <= 1)
263         return;
264 
265     SkPaint paint;
266     SkPath path;
267 
268     path.incReserve(numPoints);
269     path.moveTo(SkFloatToScalar(points[0].x()), SkFloatToScalar(points[0].y()));
270     for (size_t i = 1; i < numPoints; i++)
271         path.lineTo(SkFloatToScalar(points[i].x()), SkFloatToScalar(points[i].y()));
272 
273     if (mCanvas->quickReject(path, shouldAntialias ?
274             SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) {
275         return;
276     }
277 
278     if (m_state->fillColor & 0xFF000000) {
279         setupPaintFill(&paint);
280         paint.setAntiAlias(shouldAntialias);
281         mCanvas->drawPath(path, paint);
282     }
283 
284     if (m_state->strokeStyle != NoStroke) {
285         paint.reset();
286         setupPaintStroke(&paint, 0);
287         paint.setAntiAlias(shouldAntialias);
288         mCanvas->drawPath(path, paint);
289     }
290 }
291 
drawEllipse(const IntRect & rect)292 void PlatformGraphicsContextSkia::drawEllipse(const IntRect& rect)
293 {
294     SkPaint paint;
295     SkRect oval(rect);
296 
297     if (m_state->fillColor & 0xFF000000) {
298         setupPaintFill(&paint);
299         mCanvas->drawOval(oval, paint);
300     }
301     if (m_state->strokeStyle != NoStroke) {
302         paint.reset();
303         setupPaintStroke(&paint, &oval);
304         mCanvas->drawOval(oval, paint);
305     }
306 }
307 
drawFocusRing(const Vector<IntRect> & rects,int,int,const Color & color)308 void PlatformGraphicsContextSkia::drawFocusRing(const Vector<IntRect>& rects,
309                                             int /* width */, int /* offset */,
310                                             const Color& color)
311 {
312     unsigned rectCount = rects.size();
313     if (!rectCount)
314         return;
315 
316     SkRegion focusRingRegion;
317     const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.8);
318     for (unsigned i = 0; i < rectCount; i++) {
319         SkIRect r = rects[i];
320         r.inset(-focusRingOutset, -focusRingOutset);
321         focusRingRegion.op(r, SkRegion::kUnion_Op);
322     }
323 
324     SkPath path;
325     SkPaint paint;
326     paint.setAntiAlias(true);
327     paint.setStyle(SkPaint::kStroke_Style);
328 
329     paint.setColor(color.rgb());
330     paint.setStrokeWidth(focusRingOutset * 2);
331     paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
332     focusRingRegion.getBoundaryPath(&path);
333     mCanvas->drawPath(path, paint);
334 }
335 
drawHighlightForText(const Font & font,const TextRun & run,const FloatPoint & point,int h,const Color & backgroundColor,ColorSpace colorSpace,int from,int to,bool isActive)336 void PlatformGraphicsContextSkia::drawHighlightForText(
337         const Font& font, const TextRun& run, const FloatPoint& point, int h,
338         const Color& backgroundColor, ColorSpace colorSpace, int from,
339         int to, bool isActive)
340 {
341     IntRect rect = (IntRect)font.selectionRectForText(run, point, h, from, to);
342     if (isActive)
343         fillRect(rect, backgroundColor);
344     else {
345         int x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height();
346         const int t = 3, t2 = t * 2;
347 
348         fillRect(IntRect(x, y, w, t), backgroundColor);
349         fillRect(IntRect(x, y+h-t, w, t), backgroundColor);
350         fillRect(IntRect(x, y+t, t, h-t2), backgroundColor);
351         fillRect(IntRect(x+w-t, y+t, t, h-t2), backgroundColor);
352     }
353 }
354 
drawLine(const IntPoint & point1,const IntPoint & point2)355 void PlatformGraphicsContextSkia::drawLine(const IntPoint& point1,
356                                        const IntPoint& point2)
357 {
358     StrokeStyle style = m_state->strokeStyle;
359     if (style == NoStroke)
360         return;
361 
362     SkPaint paint;
363     SkCanvas* canvas = mCanvas;
364     const int idx = SkAbs32(point2.x() - point1.x());
365     const int idy = SkAbs32(point2.y() - point1.y());
366 
367     // Special-case horizontal and vertical lines that are really just dots
368     if (setupPaintStroke(&paint, 0, !idy) && (!idx || !idy)) {
369         const SkScalar diameter = paint.getStrokeWidth();
370         const SkScalar radius = SkScalarHalf(diameter);
371         SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x()));
372         SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y()));
373         SkScalar dx, dy;
374         int count;
375         SkRect bounds;
376 
377         if (!idy) { // Horizontal
378             bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius);
379             x += radius;
380             dx = diameter * 2;
381             dy = 0;
382             count = idx;
383         } else { // Vertical
384             bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy));
385             y += radius;
386             dx = 0;
387             dy = diameter * 2;
388             count = idy;
389         }
390 
391         // The actual count is the number of ONs we hit alternating
392         // ON(diameter), OFF(diameter), ...
393         {
394             SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter);
395             // Now compute the number of cells (ON and OFF)
396             count = SkScalarRound(width);
397             // Now compute the number of ONs
398             count = (count + 1) >> 1;
399         }
400 
401         SkAutoMalloc storage(count * sizeof(SkPoint));
402         SkPoint* verts = (SkPoint*)storage.get();
403         // Now build the array of vertices to past to drawPoints
404         for (int i = 0; i < count; i++) {
405             verts[i].set(x, y);
406             x += dx;
407             y += dy;
408         }
409 
410         paint.setStyle(SkPaint::kFill_Style);
411         paint.setPathEffect(0);
412 
413         // Clipping to bounds is not required for correctness, but it does
414         // allow us to reject the entire array of points if we are completely
415         // offscreen. This is common in a webpage for android, where most of
416         // the content is clipped out. If drawPoints took an (optional) bounds
417         // parameter, that might even be better, as we would *just* use it for
418         // culling, and not both wacking the canvas' save/restore stack.
419         canvas->save(SkCanvas::kClip_SaveFlag);
420         canvas->clipRect(bounds);
421         canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
422         canvas->restore();
423     } else {
424         SkPoint pts[2] = { point1, point2 };
425         canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
426     }
427 }
428 
drawLineForText(const FloatPoint & pt,float width)429 void PlatformGraphicsContextSkia::drawLineForText(const FloatPoint& pt, float width)
430 {
431     SkRect r;
432     setrectForUnderline(&r, m_state->strokeThickness, pt, 0, width);
433 
434     SkPaint paint;
435     paint.setAntiAlias(true);
436     paint.setColor(m_state->strokeColor);
437 
438     mCanvas->drawRect(r, paint);
439 }
440 
drawLineForTextChecking(const FloatPoint & pt,float width,GraphicsContext::TextCheckingLineStyle)441 void PlatformGraphicsContextSkia::drawLineForTextChecking(const FloatPoint& pt,
442         float width, GraphicsContext::TextCheckingLineStyle)
443 {
444     // TODO: Should we draw different based on TextCheckingLineStyle?
445     SkRect r;
446     setrectForUnderline(&r, m_state->strokeThickness, pt, 0, width);
447 
448     SkPaint paint;
449     paint.setAntiAlias(true);
450     paint.setColor(SK_ColorRED); // Is this specified somewhere?
451 
452     mCanvas->drawRect(r, paint);
453 }
454 
drawRect(const IntRect & rect)455 void PlatformGraphicsContextSkia::drawRect(const IntRect& rect)
456 {
457     SkPaint paint;
458     SkRect r(rect);
459 
460     if (m_state->fillColor & 0xFF000000) {
461         setupPaintFill(&paint);
462         mCanvas->drawRect(r, paint);
463     }
464 
465     // According to GraphicsContext.h, stroking inside drawRect always means
466     // a stroke of 1 inside the rect.
467     if (m_state->strokeStyle != NoStroke && (m_state->strokeColor & 0xFF000000)) {
468         paint.reset();
469         setupPaintStroke(&paint, &r);
470         paint.setPathEffect(0); // No dashing please
471         paint.setStrokeWidth(SK_Scalar1); // Always just 1.0 width
472         r.inset(SK_ScalarHalf, SK_ScalarHalf); // Ensure we're "inside"
473         mCanvas->drawRect(r, paint);
474     }
475 }
476 
fillPath(const Path & pathToFill,WindRule fillRule)477 void PlatformGraphicsContextSkia::fillPath(const Path& pathToFill, WindRule fillRule)
478 {
479     SkPath* path = pathToFill.platformPath();
480     if (!path)
481         return;
482 
483     switch (fillRule) {
484     case RULE_NONZERO:
485         path->setFillType(SkPath::kWinding_FillType);
486         break;
487     case RULE_EVENODD:
488         path->setFillType(SkPath::kEvenOdd_FillType);
489         break;
490     }
491 
492     SkPaint paint;
493     setupPaintFill(&paint);
494 
495     mCanvas->drawPath(*path, paint);
496 }
497 
fillRect(const FloatRect & rect)498 void PlatformGraphicsContextSkia::fillRect(const FloatRect& rect)
499 {
500     SkPaint paint;
501     setupPaintFill(&paint);
502     mCanvas->drawRect(rect, paint);
503 }
504 
fillRect(const FloatRect & rect,const Color & color)505 void PlatformGraphicsContextSkia::fillRect(const FloatRect& rect,
506                                        const Color& color)
507 {
508     if (color.rgb() & 0xFF000000) {
509         SkPaint paint;
510 
511         setupPaintCommon(&paint);
512         paint.setColor(color.rgb()); // Punch in the specified color
513         paint.setShader(0); // In case we had one set
514 
515         // Sometimes we record and draw portions of the page, using clips
516         // for each portion. The problem with this is that webkit, sometimes,
517         // sees that we're only recording a portion, and they adjust some of
518         // their rectangle coordinates accordingly (e.g.
519         // RenderBoxModelObject::paintFillLayerExtended() which calls
520         // rect.intersect(paintInfo.rect) and then draws the bg with that
521         // rect. The result is that we end up drawing rects that are meant to
522         // seam together (one for each portion), but if the rects have
523         // fractional coordinates (e.g. we are zoomed by a fractional amount)
524         // we will double-draw those edges, resulting in visual cracks or
525         // artifacts.
526 
527         // The fix seems to be to just turn off antialasing for rects (this
528         // entry-point in GraphicsContext seems to have been sufficient,
529         // though perhaps we'll find we need to do this as well in fillRect(r)
530         // as well.) Currently setupPaintCommon() enables antialiasing.
531 
532         // Since we never show the page rotated at a funny angle, disabling
533         // antialiasing seems to have no real down-side, and it does fix the
534         // bug when we're zoomed (and drawing portions that need to seam).
535         paint.setAntiAlias(false);
536 
537         mCanvas->drawRect(rect, paint);
538     }
539 }
540 
fillRoundedRect(const IntRect & rect,const IntSize & topLeft,const IntSize & topRight,const IntSize & bottomLeft,const IntSize & bottomRight,const Color & color)541 void PlatformGraphicsContextSkia::fillRoundedRect(
542         const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
543         const IntSize& bottomLeft, const IntSize& bottomRight,
544         const Color& color)
545 {
546     SkPaint paint;
547     SkPath path;
548     SkScalar radii[8];
549 
550     radii[0] = SkIntToScalar(topLeft.width());
551     radii[1] = SkIntToScalar(topLeft.height());
552     radii[2] = SkIntToScalar(topRight.width());
553     radii[3] = SkIntToScalar(topRight.height());
554     radii[4] = SkIntToScalar(bottomRight.width());
555     radii[5] = SkIntToScalar(bottomRight.height());
556     radii[6] = SkIntToScalar(bottomLeft.width());
557     radii[7] = SkIntToScalar(bottomLeft.height());
558     path.addRoundRect(rect, radii);
559 
560     setupPaintFill(&paint);
561     paint.setColor(color.rgb());
562     mCanvas->drawPath(path, paint);
563 }
564 
strokeArc(const IntRect & r,int startAngle,int angleSpan)565 void PlatformGraphicsContextSkia::strokeArc(const IntRect& r, int startAngle,
566                                         int angleSpan)
567 {
568     SkPath path;
569     SkPaint paint;
570     SkRect oval(r);
571 
572     if (m_state->strokeStyle == NoStroke) {
573         setupPaintFill(&paint); // We want the fill color
574         paint.setStyle(SkPaint::kStroke_Style);
575         paint.setStrokeWidth(SkFloatToScalar(m_state->strokeThickness));
576     } else
577         setupPaintStroke(&paint, 0);
578 
579     // We do this before converting to scalar, so we don't overflow SkFixed
580     startAngle = fastMod(startAngle, 360);
581     angleSpan = fastMod(angleSpan, 360);
582 
583     path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
584     mCanvas->drawPath(path, paint);
585 }
586 
strokePath(const Path & pathToStroke)587 void PlatformGraphicsContextSkia::strokePath(const Path& pathToStroke)
588 {
589     const SkPath* path = pathToStroke.platformPath();
590     if (!path)
591         return;
592 
593     SkPaint paint;
594     setupPaintStroke(&paint, 0);
595 
596     mCanvas->drawPath(*path, paint);
597 }
598 
strokeRect(const FloatRect & rect,float lineWidth)599 void PlatformGraphicsContextSkia::strokeRect(const FloatRect& rect, float lineWidth)
600 {
601     SkPaint paint;
602 
603     setupPaintStroke(&paint, 0);
604     paint.setStrokeWidth(SkFloatToScalar(lineWidth));
605     mCanvas->drawRect(rect, paint);
606 }
607 
608 }   // WebCore
609