Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(664)

Side by Side Diff: webkit/pending/CanvasRenderingContext2D.cpp

Issue 6500: Cleaning up the unfork (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/pending/CanvasRenderingContext2D.h ('k') | webkit/pending/CanvasRenderingContext2D.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Trolltech ASA
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "CanvasRenderingContext2D.h"
31
32 #include "AffineTransform.h"
33 #include "CSSParser.h"
34 #include "CachedImage.h"
35 #include "CanvasGradient.h"
36 #include "CanvasPattern.h"
37 #include "CanvasPixelArray.h"
38 #include "CanvasStyle.h"
39 #include "CSSPropertyNames.h"
40 #include "CSSStyleSelector.h"
41 #include "Document.h"
42 #include "ExceptionCode.h"
43 #include "FloatConversion.h"
44 #include "Frame.h"
45 #include "GraphicsContext.h"
46 #include "HTMLCanvasElement.h"
47 #include "HTMLImageElement.h"
48 #include "HTMLNames.h"
49 #include "ImageBuffer.h"
50 #include "ImageData.h"
51 #include "KURL.h"
52 #include "NotImplemented.h"
53 #include "Page.h"
54 #include "RenderHTMLCanvas.h"
55 #include "SecurityOrigin.h"
56 #include "Settings.h"
57 #include "TextMetrics.h"
58 #include <kjs/interpreter.h>
59 #include <stdio.h>
60 #include <wtf/MathExtras.h>
61
62 using namespace std;
63
64 namespace WebCore {
65
66 using namespace HTMLNames;
67
68 const char* defaultFont = "10px sans-serif";
69
70 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas)
71 : m_canvas(canvas)
72 , m_stateStack(1)
73 #if USE(V8)
74 , m_peer(0)
75 #endif
76 {
77 }
78
79 void CanvasRenderingContext2D::ref()
80 {
81 m_canvas->ref();
82 }
83
84 void CanvasRenderingContext2D::deref()
85 {
86 m_canvas->deref();
87 }
88
89 void CanvasRenderingContext2D::reset()
90 {
91 m_stateStack.resize(1);
92 m_stateStack.first() = State();
93 }
94
95 CanvasRenderingContext2D::State::State()
96 : m_strokeStyle(CanvasStyle::create("black"))
97 , m_fillStyle(CanvasStyle::create("black"))
98 , m_lineWidth(1)
99 , m_lineCap(ButtCap)
100 , m_lineJoin(MiterJoin)
101 , m_miterLimit(10)
102 , m_shadowBlur(0)
103 , m_shadowColor("black")
104 , m_globalAlpha(1)
105 , m_globalComposite(CompositeSourceOver)
106 , m_textAlign(StartTextAlign)
107 , m_textBaseline(AlphabeticTextBaseline)
108 , m_unparsedFont(defaultFont)
109 , m_realizedFont(false)
110 {
111 }
112
113 void CanvasRenderingContext2D::save()
114 {
115 ASSERT(m_stateStack.size() >= 1);
116 m_stateStack.append(state());
117 GraphicsContext* c = drawingContext();
118 if (!c)
119 return;
120 c->save();
121 }
122
123 void CanvasRenderingContext2D::restore()
124 {
125 ASSERT(m_stateStack.size() >= 1);
126 if (m_stateStack.size() <= 1)
127 return;
128 m_path.transform(state().m_transform);
129 m_stateStack.removeLast();
130 m_path.transform(state().m_transform.inverse());
131 GraphicsContext* c = drawingContext();
132 if (!c)
133 return;
134 c->restore();
135 }
136
137 CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
138 {
139 return state().m_strokeStyle.get();
140 }
141
142 void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style)
143 {
144 if (!style)
145 return;
146
147 if (m_canvas->originClean()) {
148 if (CanvasPattern* pattern = style->canvasPattern()) {
149 if (!pattern->originClean())
150 m_canvas->setOriginTainted();
151 }
152 }
153
154 state().m_strokeStyle = style;
155 GraphicsContext* c = drawingContext();
156 if (!c)
157 return;
158 state().m_strokeStyle->applyStrokeColor(c);
159 }
160
161 CanvasStyle* CanvasRenderingContext2D::fillStyle() const
162 {
163 return state().m_fillStyle.get();
164 }
165
166 void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style)
167 {
168 if (!style)
169 return;
170
171 if (m_canvas->originClean()) {
172 if (CanvasPattern* pattern = style->canvasPattern()) {
173 if (!pattern->originClean())
174 m_canvas->setOriginTainted();
175 }
176 }
177
178 state().m_fillStyle = style;
179 GraphicsContext* c = drawingContext();
180 if (!c)
181 return;
182 state().m_fillStyle->applyFillColor(c);
183 }
184
185 float CanvasRenderingContext2D::lineWidth() const
186 {
187 return state().m_lineWidth;
188 }
189
190 void CanvasRenderingContext2D::setLineWidth(float width)
191 {
192 if (!(width > 0))
193 return;
194 state().m_lineWidth = width;
195 GraphicsContext* c = drawingContext();
196 if (!c)
197 return;
198 c->setStrokeThickness(width);
199 }
200
201 String CanvasRenderingContext2D::lineCap() const
202 {
203 return lineCapName(state().m_lineCap);
204 }
205
206 void CanvasRenderingContext2D::setLineCap(const String& s)
207 {
208 LineCap cap;
209 if (!parseLineCap(s, cap))
210 return;
211 state().m_lineCap = cap;
212 GraphicsContext* c = drawingContext();
213 if (!c)
214 return;
215 c->setLineCap(cap);
216 }
217
218 String CanvasRenderingContext2D::lineJoin() const
219 {
220 return lineJoinName(state().m_lineJoin);
221 }
222
223 void CanvasRenderingContext2D::setLineJoin(const String& s)
224 {
225 LineJoin join;
226 if (!parseLineJoin(s, join))
227 return;
228 state().m_lineJoin = join;
229 GraphicsContext* c = drawingContext();
230 if (!c)
231 return;
232 c->setLineJoin(join);
233 }
234
235 float CanvasRenderingContext2D::miterLimit() const
236 {
237 return state().m_miterLimit;
238 }
239
240 void CanvasRenderingContext2D::setMiterLimit(float limit)
241 {
242 if (!(limit > 0))
243 return;
244 state().m_miterLimit = limit;
245 GraphicsContext* c = drawingContext();
246 if (!c)
247 return;
248 c->setMiterLimit(limit);
249 }
250
251 float CanvasRenderingContext2D::shadowOffsetX() const
252 {
253 return state().m_shadowOffset.width();
254 }
255
256 void CanvasRenderingContext2D::setShadowOffsetX(float x)
257 {
258 state().m_shadowOffset.setWidth(x);
259 applyShadow();
260 }
261
262 float CanvasRenderingContext2D::shadowOffsetY() const
263 {
264 return state().m_shadowOffset.height();
265 }
266
267 void CanvasRenderingContext2D::setShadowOffsetY(float y)
268 {
269 state().m_shadowOffset.setHeight(y);
270 applyShadow();
271 }
272
273 float CanvasRenderingContext2D::shadowBlur() const
274 {
275 return state().m_shadowBlur;
276 }
277
278 void CanvasRenderingContext2D::setShadowBlur(float blur)
279 {
280 state().m_shadowBlur = blur;
281 applyShadow();
282 }
283
284 String CanvasRenderingContext2D::shadowColor() const
285 {
286 // FIXME: What should this return if you called setShadow with a non-string color?
287 return state().m_shadowColor;
288 }
289
290 void CanvasRenderingContext2D::setShadowColor(const String& color)
291 {
292 state().m_shadowColor = color;
293 applyShadow();
294 }
295
296 float CanvasRenderingContext2D::globalAlpha() const
297 {
298 return state().m_globalAlpha;
299 }
300
301 void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
302 {
303 if (!(alpha >= 0 && alpha <= 1))
304 return;
305 state().m_globalAlpha = alpha;
306 GraphicsContext* c = drawingContext();
307 if (!c)
308 return;
309 c->setAlpha(alpha);
310 }
311
312 String CanvasRenderingContext2D::globalCompositeOperation() const
313 {
314 return compositeOperatorName(state().m_globalComposite);
315 }
316
317 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operati on)
318 {
319 CompositeOperator op;
320 if (!parseCompositeOperator(operation, op))
321 return;
322 state().m_globalComposite = op;
323 GraphicsContext* c = drawingContext();
324 if (!c)
325 return;
326 c->setCompositeOperation(op);
327 }
328
329 void CanvasRenderingContext2D::scale(float sx, float sy)
330 {
331 GraphicsContext* c = drawingContext();
332 if (!c)
333 return;
334 c->scale(FloatSize(sx, sy));
335 state().m_transform.scale(sx, sy);
336 m_path.transform(AffineTransform().scale(1.0/sx, 1.0/sy));
337 }
338
339 void CanvasRenderingContext2D::rotate(float angleInRadians)
340 {
341 GraphicsContext* c = drawingContext();
342 if (!c)
343 return;
344 c->rotate(angleInRadians);
345 state().m_transform.rotate(angleInRadians / piDouble * 180.0);
346 m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0 ));
347 }
348
349 void CanvasRenderingContext2D::translate(float tx, float ty)
350 {
351 GraphicsContext* c = drawingContext();
352 if (!c)
353 return;
354 c->translate(tx, ty);
355 state().m_transform.translate(tx, ty);
356 m_path.transform(AffineTransform().translate(-tx, -ty));
357 }
358
359 void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
360 {
361 GraphicsContext* c = drawingContext();
362 if (!c)
363 return;
364
365 // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers
366 if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) |
367 !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
368 return;
369 AffineTransform transform(m11, m12, m21, m22, dx, dy);
370 c->concatCTM(transform);
371 state().m_transform.multiply(transform);
372 m_path.transform(transform.inverse());
373 }
374
375 void CanvasRenderingContext2D::setStrokeColor(const String& color)
376 {
377 setStrokeStyle(CanvasStyle::create(color));
378 }
379
380 void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
381 {
382 setStrokeStyle(CanvasStyle::create(grayLevel, 1));
383 }
384
385 void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
386 {
387 setStrokeStyle(CanvasStyle::create(color, alpha));
388 }
389
390 void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
391 {
392 setStrokeStyle(CanvasStyle::create(grayLevel, alpha));
393 }
394
395 void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a )
396 {
397 setStrokeStyle(CanvasStyle::create(r, g, b, a));
398 }
399
400 void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k , float a)
401 {
402 setStrokeStyle(CanvasStyle::create(c, m, y, k, a));
403 }
404
405 void CanvasRenderingContext2D::setFillColor(const String& color)
406 {
407 setFillStyle(CanvasStyle::create(color));
408 }
409
410 void CanvasRenderingContext2D::setFillColor(float grayLevel)
411 {
412 setFillStyle(CanvasStyle::create(grayLevel, 1));
413 }
414
415 void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
416 {
417 setFillStyle(CanvasStyle::create(color, 1));
418 }
419
420 void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
421 {
422 setFillStyle(CanvasStyle::create(grayLevel, alpha));
423 }
424
425 void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
426 {
427 setFillStyle(CanvasStyle::create(r, g, b, a));
428 }
429
430 void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
431 {
432 setFillStyle(CanvasStyle::create(c, m, y, k, a));
433 }
434
435 void CanvasRenderingContext2D::beginPath()
436 {
437 m_path.clear();
438 }
439
440 void CanvasRenderingContext2D::closePath()
441 {
442 m_path.closeSubpath();
443 }
444
445 void CanvasRenderingContext2D::moveTo(float x, float y)
446 {
447 if (!isfinite(x) | !isfinite(y))
448 return;
449 m_path.moveTo(FloatPoint(x, y));
450 }
451
452 void CanvasRenderingContext2D::lineTo(float x, float y)
453 {
454 if (!isfinite(x) | !isfinite(y))
455 return;
456 m_path.addLineTo(FloatPoint(x, y));
457 }
458
459 void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, f loat y)
460 {
461 if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
462 return;
463 m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y));
464 }
465
466 void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
467 {
468 if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
469 return;
470 m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), Floa tPoint(x, y));
471 }
472
473 void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, flo at r, ExceptionCode& ec)
474 {
475 ec = 0;
476 if (!isfinite(x0) | !isfinite(y0) | !isfinite(x1) | !isfinite(y1) | !isfinit e(r))
477 return;
478
479 if (r < 0) {
480 ec = INDEX_SIZE_ERR;
481 return;
482 }
483
484 m_path.addArcTo(FloatPoint(x0, y0), FloatPoint(x1, y1), r);
485 }
486
487 void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea , bool anticlockwise, ExceptionCode& ec)
488 {
489 ec = 0;
490 if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(e a))
491 return;
492
493 if (r < 0) {
494 ec = INDEX_SIZE_ERR;
495 return;
496 }
497
498 m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
499 }
500
501 static bool validateRectForCanvas(float& x, float& y, float& width, float& heigh t)
502 {
503 if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
504 return false;
505
506 if (width < 0) {
507 width = -width;
508 x -= width;
509 }
510
511 if (height < 0) {
512 height = -height;
513 y -= height;
514 }
515
516 return true;
517 }
518
519 void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
520 {
521 if (!validateRectForCanvas(x, y, width, height))
522 return;
523
524 m_path.addRect(FloatRect(x, y, width, height));
525 }
526
527 #if ENABLE(DASHBOARD_SUPPORT)
528 void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
529 {
530 if (Settings* settings = m_canvas->document()->settings())
531 if (settings->usesDashboardBackwardCompatibilityMode())
532 m_path.clear();
533 }
534 #endif
535
536 void CanvasRenderingContext2D::fill()
537 {
538 GraphicsContext* c = drawingContext();
539 if (!c)
540 return;
541
542 c->beginPath();
543 c->addPath(m_path);
544 if (!m_path.isEmpty())
545 willDraw(m_path.boundingRect());
546
547 c->fillPath();
548
549 #if ENABLE(DASHBOARD_SUPPORT)
550 clearPathForDashboardBackwardCompatibilityMode();
551 #endif
552 }
553
554 void CanvasRenderingContext2D::stroke()
555 {
556 GraphicsContext* c = drawingContext();
557 if (!c)
558 return;
559 c->beginPath();
560 c->addPath(m_path);
561
562 if (!m_path.isEmpty()) {
563 // FIXME: This is insufficient, need to use CGContextReplacePathWithStro kedPath to expand to required bounds
564 float lineWidth = state().m_lineWidth;
565 float inset = lineWidth / 2;
566 FloatRect boundingRect = m_path.boundingRect();
567 boundingRect.inflate(inset);
568 willDraw(boundingRect);
569 }
570
571 c->strokePath();
572
573 #if ENABLE(DASHBOARD_SUPPORT)
574 clearPathForDashboardBackwardCompatibilityMode();
575 #endif
576 }
577
578 void CanvasRenderingContext2D::clip()
579 {
580 GraphicsContext* c = drawingContext();
581 if (!c)
582 return;
583 c->clip(m_path);
584 #if ENABLE(DASHBOARD_SUPPORT)
585 clearPathForDashboardBackwardCompatibilityMode();
586 #endif
587 }
588
589 bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
590 {
591 GraphicsContext* c = drawingContext();
592 if (!c)
593 return false;
594 FloatPoint point(x, y);
595 // We have to invert the current transform to ensure we correctly handle the
596 // transforms applied to the current path.
597 AffineTransform ctm = state().m_transform;
598 if (!ctm.isInvertible())
599 return false;
600 FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
601 return m_path.contains(transformedPoint);
602 }
603
604 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float he ight)
605 {
606 if (!validateRectForCanvas(x, y, width, height))
607 return;
608 GraphicsContext* c = drawingContext();
609 if (!c)
610 return;
611 FloatRect rect(x, y, width, height);
612 willDraw(rect);
613 c->clearRect(rect);
614 }
615
616 void CanvasRenderingContext2D::fillRect(float x, float y, float width, float hei ght)
617 {
618 if (!validateRectForCanvas(x, y, width, height))
619 return;
620
621 GraphicsContext* c = drawingContext();
622 if (!c)
623 return;
624
625 FloatRect rect(x, y, width, height);
626 willDraw(rect);
627
628 c->save();
629 c->fillRect(rect);
630 c->restore();
631 }
632
633 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float h eight)
634 {
635 if (!validateRectForCanvas(x, y, width, height))
636 return;
637 strokeRect(x, y, width, height, state().m_lineWidth);
638 }
639
640 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float h eight, float lineWidth)
641 {
642 if (!validateRectForCanvas(x, y, width, height))
643 return;
644
645 if (!(lineWidth >= 0))
646 return;
647
648 GraphicsContext* c = drawingContext();
649 if (!c)
650 return;
651
652 FloatRect rect(x, y, width, height);
653
654 FloatRect boundingRect = rect;
655 boundingRect.inflate(lineWidth / 2);
656 willDraw(boundingRect);
657
658 c->strokeRect(rect, lineWidth);
659 }
660
661 #if PLATFORM(CG)
662 static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height)
663 {
664 // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated
665 // to the desired integer.
666 static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128) ;
667 if (width > 0)
668 width += extraShadowOffset;
669 else if (width < 0)
670 width -= extraShadowOffset;
671
672 if (height > 0)
673 height += extraShadowOffset;
674 else if (height < 0)
675 height -= extraShadowOffset;
676
677 return CGSizeMake(width, height);
678 }
679 #endif
680
681 void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
682 {
683 state().m_shadowOffset = FloatSize(width, height);
684 state().m_shadowBlur = blur;
685 state().m_shadowColor = "";
686 applyShadow();
687 }
688
689 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
690 {
691 state().m_shadowOffset = FloatSize(width, height);
692 state().m_shadowBlur = blur;
693 state().m_shadowColor = color;
694 applyShadow();
695 }
696
697 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
698 {
699 state().m_shadowOffset = FloatSize(width, height);
700 state().m_shadowBlur = blur;
701 state().m_shadowColor = "";
702
703 GraphicsContext* c = drawingContext();
704 if (!c)
705 return;
706 // FIXME: Do this through platform-independent GraphicsContext API.
707 #if PLATFORM(CG)
708 const CGFloat components[2] = { grayLevel, 1 };
709 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
710 CGColorRef color = CGColorCreate(colorSpace, components);
711 CGColorSpaceRelease(colorSpace);
712 CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, color);
713 CGColorRelease(color);
714 #endif
715 }
716
717 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
718 {
719 state().m_shadowOffset = FloatSize(width, height);
720 state().m_shadowBlur = blur;
721 state().m_shadowColor = color;
722
723 GraphicsContext* c = drawingContext();
724 if (!c)
725 return;
726 // FIXME: Do this through platform-independent GraphicsContext API.
727 #if PLATFORM(CG)
728 RGBA32 rgba = 0; // default is transparent black
729 CSSParser::parseColor(rgba, color);
730 const CGFloat components[4] = {
731 ((rgba >> 16) & 0xFF) / 255.0f,
732 ((rgba >> 8) & 0xFF) / 255.0f,
733 (rgba & 0xFF) / 255.0f,
734 alpha
735 };
736 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
737 CGColorRef shadowColor = CGColorCreate(colorSpace, components);
738 CGColorSpaceRelease(colorSpace);
739 CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
740 CGColorRelease(shadowColor);
741 #endif
742 }
743
744 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
745 {
746 state().m_shadowOffset = FloatSize(width, height);
747 state().m_shadowBlur = blur;
748 state().m_shadowColor = "";
749
750 GraphicsContext* c = drawingContext();
751 if (!c)
752 return;
753 // FIXME: Do this through platform-independent GraphicsContext API.
754 #if PLATFORM(CG)
755 const CGFloat components[2] = { grayLevel, alpha };
756 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
757 CGColorRef color = CGColorCreate(colorSpace, components);
758 CGColorSpaceRelease(colorSpace);
759 CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, color);
760 CGColorRelease(color);
761 #endif
762 }
763
764 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
765 {
766 state().m_shadowOffset = FloatSize(width, height);
767 state().m_shadowBlur = blur;
768 state().m_shadowColor = "";
769
770 GraphicsContext* c = drawingContext();
771 if (!c)
772 return;
773 // FIXME: Do this through platform-independent GraphicsContext API.
774 #if PLATFORM(CG)
775 const CGFloat components[4] = { r, g, b, a };
776 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
777 CGColorRef shadowColor = CGColorCreate(colorSpace, components);
778 CGColorSpaceRelease(colorSpace);
779 CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
780 CGColorRelease(shadowColor);
781 #endif
782 }
783
784 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
785 {
786 state().m_shadowOffset = FloatSize(width, height);
787 state().m_shadowBlur = blur;
788 state().m_shadowColor = "";
789
790 GraphicsContext* dc = drawingContext();
791 if (!dc)
792 return;
793 // FIXME: Do this through platform-independent GraphicsContext API.
794 #if PLATFORM(CG)
795 const CGFloat components[5] = { c, m, y, k, a };
796 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK();
797 CGColorRef shadowColor = CGColorCreate(colorSpace, components);
798 CGColorSpaceRelease(colorSpace);
799 CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
800 CGColorRelease(shadowColor);
801 #endif
802 }
803
804 void CanvasRenderingContext2D::clearShadow()
805 {
806 state().m_shadowOffset = FloatSize();
807 state().m_shadowBlur = 0;
808 state().m_shadowColor = "";
809 applyShadow();
810 }
811
812 void CanvasRenderingContext2D::applyShadow()
813 {
814 GraphicsContext* c = drawingContext();
815 if (!c)
816 return;
817 // FIXME: Do this through platform-independent GraphicsContext API.
818 #if PLATFORM(CG)
819 RGBA32 rgba = 0; // default is transparent black
820 if (!state().m_shadowColor.isEmpty())
821 CSSParser::parseColor(rgba, state().m_shadowColor);
822 const CGFloat components[4] = {
823 ((rgba >> 16) & 0xFF) / 255.0f,
824 ((rgba >> 8) & 0xFF) / 255.0f,
825 (rgba & 0xFF) / 255.0f,
826 ((rgba >> 24) & 0xFF) / 255.0f
827 };
828 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
829 CGColorRef color = CGColorCreate(colorSpace, components);
830 CGColorSpaceRelease(colorSpace);
831
832 CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(state() .m_shadowOffset.width(), -state().m_shadowOffset.height()), state().m_shadowBlur , color);
833 CGColorRelease(color);
834 #endif
835 }
836
837 static IntSize size(HTMLImageElement* image)
838 {
839 if (CachedImage* cachedImage = image->cachedImage())
840 return cachedImage->imageSize(1.0f); // FIXME: Not sure about this.
841 return IntSize();
842 }
843
844 static inline FloatRect normalizeRect(const FloatRect& rect)
845 {
846 return FloatRect(min(rect.x(), rect.right()),
847 min(rect.y(), rect.bottom()),
848 max(rect.width(), -rect.width()),
849 max(rect.height(), -rect.height()));
850 }
851
852 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y)
853 {
854 ASSERT(image);
855 IntSize s = size(image);
856 ExceptionCode ec;
857 drawImage(image, x, y, s.width(), s.height(), ec);
858 }
859
860 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
861 float x, float y, float width, float height, ExceptionCode& ec)
862 {
863 ASSERT(image);
864 IntSize s = size(image);
865 drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, wid th, height), ec);
866 }
867
868 void CanvasRenderingContext2D::checkOrigin(const KURL& url)
869 {
870 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
871 if (!m_canvas->document()->securityOrigin()->canAccess(origin.get()))
872 m_canvas->setOriginTainted();
873 }
874
875 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec t& srcRect, const FloatRect& dstRect,
876 ExceptionCode& ec)
877 {
878 ASSERT(image);
879
880 ec = 0;
881
882 FloatRect imageRect = FloatRect(FloatPoint(), size(image));
883 if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || s rcRect.height() == 0) {
884 ec = INDEX_SIZE_ERR;
885 return;
886 }
887
888 if (!dstRect.width() || !dstRect.height())
889 return;
890
891 GraphicsContext* c = drawingContext();
892 if (!c)
893 return;
894
895 CachedImage* cachedImage = image->cachedImage();
896 if (!cachedImage)
897 return;
898
899 if (m_canvas->originClean())
900 checkOrigin(cachedImage->response().url());
901
902 if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigi n())
903 m_canvas->setOriginTainted();
904
905 FloatRect sourceRect = c->roundToDevicePixels(srcRect);
906 FloatRect destRect = c->roundToDevicePixels(dstRect);
907 willDraw(destRect);
908 c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalCom posite);
909 }
910
911 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, flo at y)
912 {
913 ASSERT(canvas);
914 ExceptionCode ec;
915 drawImage(canvas, x, y, canvas->width(), canvas->height(), ec);
916 }
917
918 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
919 float x, float y, float width, float height, ExceptionCode& ec)
920 {
921 ASSERT(canvas);
922 drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatR ect(x, y, width, height), ec);
923 }
924
925 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatR ect& srcRect,
926 const FloatRect& dstRect, ExceptionCode& ec)
927 {
928 ASSERT(canvas);
929
930 ec = 0;
931
932 FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size());
933 if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
934 ec = INDEX_SIZE_ERR;
935 return;
936 }
937
938 if (!dstRect.width() || !dstRect.height())
939 return;
940
941 GraphicsContext* c = drawingContext();
942 if (!c)
943 return;
944
945 FloatRect sourceRect = c->roundToDevicePixels(srcRect);
946 FloatRect destRect = c->roundToDevicePixels(dstRect);
947
948 // FIXME: Do this through platform-independent GraphicsContext API.
949 ImageBuffer* buffer = canvas->buffer();
950 if (!buffer)
951 return;
952
953 if (!canvas->originClean())
954 m_canvas->setOriginTainted();
955
956 c->drawImage(buffer->image(), destRect, sourceRect, state().m_globalComposit e);
957 willDraw(destRect); // This call comes after drawImage, since the buffer we draw into may be our own, and we need to make sure it is dirty.
958 // FIXME: Arguably willDraw should become didDraw and oc cur after drawing calls and not before them to avoid problems like this.
959 }
960
961 // FIXME: Why isn't this just another overload of drawImage? Why have a differen t name?
962 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
963 float sx, float sy, float sw, float sh,
964 float dx, float dy, float dw, float dh,
965 const String& compositeOperation)
966 {
967 if (!image)
968 return;
969
970 CachedImage* cachedImage = image->cachedImage();
971 if (!cachedImage)
972 return;
973
974 if (m_canvas->originClean())
975 checkOrigin(cachedImage->response().url());
976
977 if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigi n())
978 m_canvas->setOriginTainted();
979
980 GraphicsContext* c = drawingContext();
981 if (!c)
982 return;
983
984 CompositeOperator op;
985 if (!parseCompositeOperator(compositeOperation, op))
986 op = CompositeSourceOver;
987
988 FloatRect destRect = FloatRect(dx, dy, dw, dh);
989 willDraw(destRect);
990 c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op);
991 }
992
993 void CanvasRenderingContext2D::setAlpha(float alpha)
994 {
995 setGlobalAlpha(alpha);
996 }
997
998 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
999 {
1000 setGlobalCompositeOperation(operation);
1001 }
1002
1003 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1)
1004 {
1005 return CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1006 }
1007
1008 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1)
1009 {
1010 return CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1 );
1011 }
1012
1013 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageEleme nt* image,
1014 const String& repetitionType, ExceptionCode& ec)
1015 {
1016 bool repeatX, repeatY;
1017 ec = 0;
1018 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1019 if (ec)
1020 return 0;
1021
1022 if (!image->complete()) {
1023 ec = INVALID_STATE_ERR;
1024 return 0;
1025 }
1026
1027 CachedImage* cachedImage = image->cachedImage();
1028 if (!cachedImage || !image->cachedImage()->image())
1029 return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true) ;
1030
1031 KURL url(cachedImage->url());
1032 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
1033 bool originClean = m_canvas->document()->securityOrigin()->canAccess(origin. get());
1034 return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originC lean);
1035 }
1036
1037 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElem ent* canvas,
1038 const String& repetitionType, ExceptionCode& ec)
1039 {
1040 bool repeatX, repeatY;
1041 ec = 0;
1042 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1043 if (ec)
1044 return 0;
1045 return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, ca nvas->originClean());
1046 }
1047
1048 void CanvasRenderingContext2D::willDraw(const FloatRect& r)
1049 {
1050 GraphicsContext* c = drawingContext();
1051 if (!c)
1052 return;
1053
1054 m_canvas->willDraw(c->getCTM().mapRect(r));
1055 }
1056
1057 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1058 {
1059 return m_canvas->drawingContext();
1060 }
1061
1062 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
1063 {
1064 PassRefPtr<ImageData> data = ImageData::create(size.width(), size.height());
1065 memset(data->data()->data().data(), 0, data->data()->length());
1066 return data;
1067 }
1068
1069 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh) const
1070 {
1071 FloatSize unscaledSize(sw, sh);
1072 IntSize scaledSize = m_canvas->convertLogicalToDevice(unscaledSize);
1073 if (scaledSize.width() < 1)
1074 scaledSize.setWidth(1);
1075 if (scaledSize.height() < 1)
1076 scaledSize.setHeight(1);
1077
1078 return createEmptyImageData(scaledSize);
1079 }
1080
1081 PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
1082 {
1083 if (!m_canvas->originClean()) {
1084 ec = SECURITY_ERR;
1085 return 0;
1086 }
1087
1088 FloatRect unscaledRect(sx, sy, sw, sh);
1089 IntRect scaledRect = m_canvas->convertLogicalToDevice(unscaledRect);
1090 if (scaledRect.width() < 1)
1091 scaledRect.setWidth(1);
1092 if (scaledRect.height() < 1)
1093 scaledRect.setHeight(1);
1094 ImageBuffer* buffer = m_canvas ? m_canvas->buffer() : 0;
1095 if (!buffer)
1096 return createEmptyImageData(scaledRect.size());
1097 return buffer->getImageData(scaledRect);
1098 }
1099
1100 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
1101 {
1102 if (!data) {
1103 ec = TYPE_MISMATCH_ERR;
1104 return;
1105 }
1106 putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
1107 }
1108
1109 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY,
1110 float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
1111 {
1112 if (!data) {
1113 ec = TYPE_MISMATCH_ERR;
1114 return;
1115 }
1116 if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) ||
1117 !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
1118 ec = INDEX_SIZE_ERR;
1119 return;
1120 }
1121
1122 ImageBuffer* buffer = m_canvas->buffer();
1123 if (!buffer)
1124 return;
1125
1126 if (dirtyWidth < 0) {
1127 dirtyX += dirtyWidth;
1128 dirtyWidth = -dirtyWidth;
1129 }
1130
1131 if (dirtyHeight < 0) {
1132 dirtyY += dirtyHeight;
1133 dirtyHeight = -dirtyHeight;
1134 }
1135
1136 FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1137 clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1138 IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1139 IntRect sourceRect = enclosingIntRect(clipRect);
1140 sourceRect.move(destOffset);
1141 sourceRect.intersect(IntRect(IntPoint(), buffer->size()));
1142 if (sourceRect.isEmpty())
1143 return;
1144 willDraw(sourceRect);
1145 sourceRect.move(-destOffset);
1146 IntPoint destPoint(destOffset.width(), destOffset.height());
1147
1148 buffer->putImageData(data, sourceRect, destPoint);
1149 }
1150
1151 String CanvasRenderingContext2D::font() const
1152 {
1153 return state().m_unparsedFont;
1154 }
1155
1156 void CanvasRenderingContext2D::setFont(const String& newFont)
1157 {
1158 RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::cr eate();
1159 CSSParser parser(!m_canvas->document()->inCompatMode()); // Use the parse mo de of the canvas' document when parsing CSS.
1160
1161 String declarationText("font: ");
1162 declarationText += newFont;
1163 parser.parseDeclaration(tempDecl.get(), declarationText);
1164 if (!tempDecl->length())
1165 return;
1166
1167 // The parse succeeded.
1168 state().m_unparsedFont = newFont;
1169
1170 // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1171 // relative to the canvas.
1172 RenderArena* arena = m_canvas->document()->renderArena();
1173 RenderStyle* newStyle = new (arena) RenderStyle();
1174 newStyle->ref();
1175 if (m_canvas->computedStyle())
1176 newStyle->setFontDescription(m_canvas->computedStyle()->fontDescription( ));
1177
1178 // Now map the font property into the style.
1179 CSSStyleSelector* styleSelector = m_canvas->document()->styleSelector();
1180 styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCS SValue(CSSPropertyFont).get(), newStyle);
1181
1182 state().m_font = newStyle->font();
1183 state().m_font.update(styleSelector->fontSelector());
1184 state().m_realizedFont = true;
1185
1186 newStyle->deref(arena);
1187
1188 // Set the font in the graphics context.
1189 GraphicsContext* c = drawingContext();
1190 if (!c)
1191 return;
1192 c->setFont(state().m_font);
1193 }
1194
1195 String CanvasRenderingContext2D::textAlign() const
1196 {
1197 return textAlignName(state().m_textAlign);
1198 }
1199
1200 void CanvasRenderingContext2D::setTextAlign(const String& s)
1201 {
1202 TextAlign align;
1203 if (!parseTextAlign(s, align))
1204 return;
1205 state().m_textAlign = align;
1206 }
1207
1208 String CanvasRenderingContext2D::textBaseline() const
1209 {
1210 return textBaselineName(state().m_textBaseline);
1211 }
1212
1213 void CanvasRenderingContext2D::setTextBaseline(const String& s)
1214 {
1215 TextBaseline baseline;
1216 if (!parseTextBaseline(s, baseline))
1217 return;
1218 state().m_textBaseline = baseline;
1219 }
1220
1221 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
1222 {
1223 drawTextInternal(text, x, y, true);
1224 }
1225
1226 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, fl oat maxWidth)
1227 {
1228 drawTextInternal(text, x, y, true, maxWidth, true);
1229 }
1230
1231 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
1232 {
1233 drawTextInternal(text, x, y, false);
1234 }
1235
1236 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
1237 {
1238 drawTextInternal(text, x, y, false, maxWidth, true);
1239 }
1240
1241 PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text )
1242 {
1243 RefPtr<TextMetrics> metrics = TextMetrics::create();
1244 metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length( ))));
1245 return metrics;
1246 }
1247
1248 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo at y, bool fill, float maxWidth, bool useMaxWidth)
1249 {
1250 GraphicsContext* c = drawingContext();
1251 if (!c)
1252 return;
1253
1254 const Font& font = accessFont();
1255
1256 // FIXME: Handle maxWidth.
1257 // FIXME: Need to turn off font smoothing.
1258
1259 bool rtl = m_canvas->computedStyle() ? m_canvas->computedStyle()->direction( ) == RTL : false;
1260 bool override = m_canvas->computedStyle() ? m_canvas->computedStyle()->unico deBidi() == Override : false;
1261
1262 unsigned length = text.length();
1263 const UChar* string = text.characters();
1264 TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false);
1265
1266 // Draw the item text at the correct point.
1267 FloatPoint location(x, y);
1268 switch (state().m_textBaseline) {
1269 case TopTextBaseline:
1270 case HangingTextBaseline:
1271 location.setY(y + font.ascent());
1272 break;
1273 case BottomTextBaseline:
1274 case IdeographicTextBaseline:
1275 location.setY(y - font.descent());
1276 break;
1277 case MiddleTextBaseline:
1278 location.setY(y - font.descent() + font.height() / 2);
1279 break;
1280 case AlphabeticTextBaseline:
1281 default:
1282 // Do nothing.
1283 break;
1284 }
1285
1286 float width = font.width(TextRun(text, false, 0, 0, rtl, override));
1287
1288 TextAlign align = state().m_textAlign;
1289 if (align == StartTextAlign)
1290 align = rtl ? RightTextAlign : LeftTextAlign;
1291 else if (align == EndTextAlign)
1292 align = rtl ? LeftTextAlign : RightTextAlign;
1293
1294 switch (align) {
1295 case CenterTextAlign:
1296 location.setX(location.x() - width / 2);
1297 break;
1298 case RightTextAlign:
1299 location.setX(location.x() - width);
1300 break;
1301 default:
1302 break;
1303 }
1304
1305 // The slop built in to this mask rect matches the heuristic used in FontCGW in.cpp for GDI text.
1306 FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y( ) - font.ascent() - font.lineGap(),
1307 width + font.height(), font.lineSpacing());
1308 if (!fill)
1309 textRect.inflate(c->strokeThickness() / 2);
1310
1311 CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_stroke Style.get();
1312 if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
1313 IntRect maskRect = enclosingIntRect(textRect);
1314
1315 auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), f alse);
1316
1317 GraphicsContext* maskImageContext = maskImage->context();
1318
1319 if (fill)
1320 maskImageContext->setFillColor(Color::black);
1321 else {
1322 maskImageContext->setStrokeColor(Color::black);
1323 maskImageContext->setStrokeThickness(c->strokeThickness());
1324 }
1325
1326 maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1327 maskImageContext->translate(-maskRect.x(), -maskRect.y());
1328
1329 maskImageContext->setFont(font);
1330 maskImageContext->drawBidiText(textRun, location);
1331
1332 c->save();
1333 c->clipToImageBuffer(maskRect, maskImage.get());
1334 drawStyle->applyFillColor(c);
1335 c->fillRect(maskRect);
1336 c->restore();
1337
1338 return;
1339 }
1340
1341 c->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1342 c->drawBidiText(textRun, location);
1343 }
1344
1345 const Font& CanvasRenderingContext2D::accessFont()
1346 {
1347 if (!state().m_realizedFont)
1348 setFont(state().m_unparsedFont);
1349 return state().m_font;
1350 }
1351
1352 } // namespace WebCore
OLDNEW
« no previous file with comments | « webkit/pending/CanvasRenderingContext2D.h ('k') | webkit/pending/CanvasRenderingContext2D.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698