WebCore/html/canvas/CanvasRenderingContext2D.cpp
changeset 0 4f2f89ce4247
child 2 303757a437d3
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     3  * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
       
     4  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
       
     5  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
       
     6  * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
       
     7  * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
       
     8  *
       
     9  * Redistribution and use in source and binary forms, with or without
       
    10  * modification, are permitted provided that the following conditions
       
    11  * are met:
       
    12  * 1. Redistributions of source code must retain the above copyright
       
    13  *    notice, this list of conditions and the following disclaimer.
       
    14  * 2. Redistributions in binary form must reproduce the above copyright
       
    15  *    notice, this list of conditions and the following disclaimer in the
       
    16  *    documentation and/or other materials provided with the distribution.
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    26  * 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 "CanvasRenderingContext2D.h"
       
    33 
       
    34 #include "AffineTransform.h"
       
    35 #include "CSSParser.h"
       
    36 #include "CachedImage.h"
       
    37 #include "CanvasGradient.h"
       
    38 #include "CanvasPattern.h"
       
    39 #include "CanvasStyle.h"
       
    40 #include "CSSMutableStyleDeclaration.h"
       
    41 #include "CSSPropertyNames.h"
       
    42 #include "CSSStyleSelector.h"
       
    43 #include "ExceptionCode.h"
       
    44 #include "FloatConversion.h"
       
    45 #include "GraphicsContext.h"
       
    46 #include "HTMLCanvasElement.h"
       
    47 #include "HTMLImageElement.h"
       
    48 #include "HTMLMediaElement.h"
       
    49 #include "HTMLNames.h"
       
    50 #include "ImageBuffer.h"
       
    51 #include "ImageData.h"
       
    52 #include "KURL.h"
       
    53 #include "Page.h"
       
    54 #include "RenderHTMLCanvas.h"
       
    55 #include "SecurityOrigin.h"
       
    56 #include "Settings.h"
       
    57 #include "StrokeStyleApplier.h"
       
    58 #include "TextMetrics.h"
       
    59 #include "HTMLVideoElement.h"
       
    60 #include <stdio.h>
       
    61 #include <wtf/ByteArray.h>
       
    62 #include <wtf/MathExtras.h>
       
    63 #include <wtf/OwnPtr.h>
       
    64 #include <wtf/UnusedParam.h>
       
    65 
       
    66 using namespace std;
       
    67 
       
    68 namespace WebCore {
       
    69 
       
    70 using namespace HTMLNames;
       
    71 
       
    72 static const char* const defaultFont = "10px sans-serif";
       
    73 
       
    74 
       
    75 class CanvasStrokeStyleApplier : public StrokeStyleApplier {
       
    76 public:
       
    77     CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
       
    78         : m_canvasContext(canvasContext)
       
    79     {
       
    80     }
       
    81     
       
    82     virtual void strokeStyle(GraphicsContext* c)
       
    83     {
       
    84         c->setStrokeThickness(m_canvasContext->lineWidth());
       
    85         c->setLineCap(m_canvasContext->getLineCap());
       
    86         c->setLineJoin(m_canvasContext->getLineJoin());
       
    87         c->setMiterLimit(m_canvasContext->miterLimit());
       
    88     }
       
    89 
       
    90 private:
       
    91     CanvasRenderingContext2D* m_canvasContext;
       
    92 };
       
    93 
       
    94 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode)
       
    95     : CanvasRenderingContext(canvas)
       
    96     , m_stateStack(1)
       
    97     , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
       
    98 #if ENABLE(DASHBOARD_SUPPORT)
       
    99     , m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode)
       
   100 #endif
       
   101 {
       
   102 #if !ENABLE(DASHBOARD_SUPPORT)
       
   103    ASSERT_UNUSED(usesDashboardCompatibilityMode, !usesDashboardCompatibilityMode);
       
   104 #endif
       
   105 
       
   106     // Make sure that even if the drawingContext() has a different default
       
   107     // thickness, it is in sync with the canvas thickness.
       
   108     setLineWidth(lineWidth());
       
   109 }
       
   110 
       
   111 CanvasRenderingContext2D::~CanvasRenderingContext2D()
       
   112 {
       
   113 }
       
   114 
       
   115 void CanvasRenderingContext2D::reset()
       
   116 {
       
   117     m_stateStack.resize(1);
       
   118     m_stateStack.first() = State();
       
   119     m_path.clear();
       
   120 }
       
   121 
       
   122 CanvasRenderingContext2D::State::State()
       
   123     : m_strokeStyle(CanvasStyle::create(Color::black))
       
   124     , m_fillStyle(CanvasStyle::create(Color::black))
       
   125     , m_lineWidth(1)
       
   126     , m_lineCap(ButtCap)
       
   127     , m_lineJoin(MiterJoin)
       
   128     , m_miterLimit(10)
       
   129     , m_shadowBlur(0)
       
   130     , m_shadowColor(Color::transparent)
       
   131     , m_globalAlpha(1)
       
   132     , m_globalComposite(CompositeSourceOver)
       
   133     , m_invertibleCTM(true)
       
   134     , m_textAlign(StartTextAlign)
       
   135     , m_textBaseline(AlphabeticTextBaseline)
       
   136     , m_unparsedFont(defaultFont)
       
   137     , m_realizedFont(false)
       
   138 {
       
   139 }
       
   140 
       
   141 void CanvasRenderingContext2D::save()
       
   142 {
       
   143     ASSERT(m_stateStack.size() >= 1);
       
   144     m_stateStack.append(state());
       
   145     GraphicsContext* c = drawingContext();
       
   146     if (!c)
       
   147         return;
       
   148     c->save();
       
   149 }
       
   150 
       
   151 void CanvasRenderingContext2D::restore()
       
   152 {
       
   153     ASSERT(m_stateStack.size() >= 1);
       
   154     if (m_stateStack.size() <= 1)
       
   155         return;
       
   156     m_path.transform(state().m_transform);
       
   157     m_stateStack.removeLast();
       
   158     m_path.transform(state().m_transform.inverse());
       
   159     GraphicsContext* c = drawingContext();
       
   160     if (!c)
       
   161         return;
       
   162     c->restore();
       
   163 }
       
   164 
       
   165 CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
       
   166 {
       
   167     return state().m_strokeStyle.get();
       
   168 }
       
   169 
       
   170 void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style)
       
   171 {
       
   172     if (!style)
       
   173         return;
       
   174 
       
   175     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style))
       
   176         return;
       
   177 
       
   178     if (canvas()->originClean()) {
       
   179         if (CanvasPattern* pattern = style->canvasPattern()) {
       
   180             if (!pattern->originClean())
       
   181                 canvas()->setOriginTainted();
       
   182         }
       
   183     }
       
   184 
       
   185     state().m_strokeStyle = style;
       
   186     GraphicsContext* c = drawingContext();
       
   187     if (!c)
       
   188         return;
       
   189     state().m_strokeStyle->applyStrokeColor(c);
       
   190     state().m_unparsedStrokeColor = String();
       
   191 }
       
   192 
       
   193 CanvasStyle* CanvasRenderingContext2D::fillStyle() const
       
   194 {
       
   195     return state().m_fillStyle.get();
       
   196 }
       
   197 
       
   198 void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style)
       
   199 {
       
   200     if (!style)
       
   201         return;
       
   202 
       
   203     if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style))
       
   204         return;
       
   205  
       
   206     if (canvas()->originClean()) {
       
   207         if (CanvasPattern* pattern = style->canvasPattern()) {
       
   208             if (!pattern->originClean())
       
   209                 canvas()->setOriginTainted();
       
   210         }
       
   211     }
       
   212 
       
   213     state().m_fillStyle = style;
       
   214     GraphicsContext* c = drawingContext();
       
   215     if (!c)
       
   216         return;
       
   217     state().m_fillStyle->applyFillColor(c);
       
   218     state().m_unparsedFillColor = String();
       
   219 }
       
   220 
       
   221 float CanvasRenderingContext2D::lineWidth() const
       
   222 {
       
   223     return state().m_lineWidth;
       
   224 }
       
   225 
       
   226 void CanvasRenderingContext2D::setLineWidth(float width)
       
   227 {
       
   228     if (!(isfinite(width) && width > 0))
       
   229         return;
       
   230     state().m_lineWidth = width;
       
   231     GraphicsContext* c = drawingContext();
       
   232     if (!c)
       
   233         return;
       
   234     c->setStrokeThickness(width);
       
   235 }
       
   236 
       
   237 String CanvasRenderingContext2D::lineCap() const
       
   238 {
       
   239     return lineCapName(state().m_lineCap);
       
   240 }
       
   241 
       
   242 void CanvasRenderingContext2D::setLineCap(const String& s)
       
   243 {
       
   244     LineCap cap;
       
   245     if (!parseLineCap(s, cap))
       
   246         return;
       
   247     state().m_lineCap = cap;
       
   248     GraphicsContext* c = drawingContext();
       
   249     if (!c)
       
   250         return;
       
   251     c->setLineCap(cap);
       
   252 }
       
   253 
       
   254 String CanvasRenderingContext2D::lineJoin() const
       
   255 {
       
   256     return lineJoinName(state().m_lineJoin);
       
   257 }
       
   258 
       
   259 void CanvasRenderingContext2D::setLineJoin(const String& s)
       
   260 {
       
   261     LineJoin join;
       
   262     if (!parseLineJoin(s, join))
       
   263         return;
       
   264     state().m_lineJoin = join;
       
   265     GraphicsContext* c = drawingContext();
       
   266     if (!c)
       
   267         return;
       
   268     c->setLineJoin(join);
       
   269 }
       
   270 
       
   271 float CanvasRenderingContext2D::miterLimit() const
       
   272 {
       
   273     return state().m_miterLimit;
       
   274 }
       
   275 
       
   276 void CanvasRenderingContext2D::setMiterLimit(float limit)
       
   277 {
       
   278     if (!(isfinite(limit) && limit > 0))
       
   279         return;
       
   280     state().m_miterLimit = limit;
       
   281     GraphicsContext* c = drawingContext();
       
   282     if (!c)
       
   283         return;
       
   284     c->setMiterLimit(limit);
       
   285 }
       
   286 
       
   287 float CanvasRenderingContext2D::shadowOffsetX() const
       
   288 {
       
   289     return state().m_shadowOffset.width();
       
   290 }
       
   291 
       
   292 void CanvasRenderingContext2D::setShadowOffsetX(float x)
       
   293 {
       
   294     if (!isfinite(x))
       
   295         return;
       
   296     state().m_shadowOffset.setWidth(x);
       
   297     applyShadow();
       
   298 }
       
   299 
       
   300 float CanvasRenderingContext2D::shadowOffsetY() const
       
   301 {
       
   302     return state().m_shadowOffset.height();
       
   303 }
       
   304 
       
   305 void CanvasRenderingContext2D::setShadowOffsetY(float y)
       
   306 {
       
   307     if (!isfinite(y))
       
   308         return;
       
   309     state().m_shadowOffset.setHeight(y);
       
   310     applyShadow();
       
   311 }
       
   312 
       
   313 float CanvasRenderingContext2D::shadowBlur() const
       
   314 {
       
   315     return state().m_shadowBlur;
       
   316 }
       
   317 
       
   318 void CanvasRenderingContext2D::setShadowBlur(float blur)
       
   319 {
       
   320     if (!(isfinite(blur) && blur >= 0))
       
   321         return;
       
   322     state().m_shadowBlur = blur;
       
   323     applyShadow();
       
   324 }
       
   325 
       
   326 String CanvasRenderingContext2D::shadowColor() const
       
   327 {
       
   328     return Color(state().m_shadowColor).serialized();
       
   329 }
       
   330 
       
   331 void CanvasRenderingContext2D::setShadowColor(const String& color)
       
   332 {
       
   333     if (!CSSParser::parseColor(state().m_shadowColor, color))
       
   334         return;
       
   335 
       
   336     applyShadow();
       
   337 }
       
   338 
       
   339 float CanvasRenderingContext2D::globalAlpha() const
       
   340 {
       
   341     return state().m_globalAlpha;
       
   342 }
       
   343 
       
   344 void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
       
   345 {
       
   346     if (!(alpha >= 0 && alpha <= 1))
       
   347         return;
       
   348     state().m_globalAlpha = alpha;
       
   349     GraphicsContext* c = drawingContext();
       
   350     if (!c)
       
   351         return;
       
   352     c->setAlpha(alpha);
       
   353 }
       
   354 
       
   355 String CanvasRenderingContext2D::globalCompositeOperation() const
       
   356 {
       
   357     return compositeOperatorName(state().m_globalComposite);
       
   358 }
       
   359 
       
   360 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
       
   361 {
       
   362     CompositeOperator op;
       
   363     if (!parseCompositeOperator(operation, op))
       
   364         return;
       
   365     state().m_globalComposite = op;
       
   366     GraphicsContext* c = drawingContext();
       
   367     if (!c)
       
   368         return;
       
   369     c->setCompositeOperation(op);
       
   370 }
       
   371 
       
   372 void CanvasRenderingContext2D::scale(float sx, float sy)
       
   373 {
       
   374     GraphicsContext* c = drawingContext();
       
   375     if (!c)
       
   376         return;
       
   377     if (!state().m_invertibleCTM)
       
   378         return;
       
   379 
       
   380     if (!isfinite(sx) | !isfinite(sy))
       
   381         return;
       
   382 
       
   383     AffineTransform newTransform = state().m_transform;
       
   384     newTransform.scaleNonUniform(sx, sy);
       
   385     if (!newTransform.isInvertible()) {
       
   386         state().m_invertibleCTM = false;
       
   387         return;
       
   388     }
       
   389 
       
   390     state().m_transform = newTransform;
       
   391     c->scale(FloatSize(sx, sy));
       
   392     m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
       
   393 }
       
   394 
       
   395 void CanvasRenderingContext2D::rotate(float angleInRadians)
       
   396 {
       
   397     GraphicsContext* c = drawingContext();
       
   398     if (!c)
       
   399         return;
       
   400     if (!state().m_invertibleCTM)
       
   401         return;
       
   402 
       
   403     if (!isfinite(angleInRadians))
       
   404         return;
       
   405 
       
   406     AffineTransform newTransform = state().m_transform;
       
   407     newTransform.rotate(angleInRadians / piDouble * 180.0);
       
   408     if (!newTransform.isInvertible()) {
       
   409         state().m_invertibleCTM = false;
       
   410         return;
       
   411     }
       
   412 
       
   413     state().m_transform = newTransform;
       
   414     c->rotate(angleInRadians);
       
   415     m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
       
   416 }
       
   417 
       
   418 void CanvasRenderingContext2D::translate(float tx, float ty)
       
   419 {
       
   420     GraphicsContext* c = drawingContext();
       
   421     if (!c)
       
   422         return;
       
   423     if (!state().m_invertibleCTM)
       
   424         return;
       
   425 
       
   426     if (!isfinite(tx) | !isfinite(ty))
       
   427         return;
       
   428 
       
   429     AffineTransform newTransform = state().m_transform;
       
   430     newTransform.translate(tx, ty);
       
   431     if (!newTransform.isInvertible()) {
       
   432         state().m_invertibleCTM = false;
       
   433         return;
       
   434     }
       
   435 
       
   436     state().m_transform = newTransform;
       
   437     c->translate(tx, ty);
       
   438     m_path.transform(AffineTransform().translate(-tx, -ty));
       
   439 }
       
   440 
       
   441 void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
       
   442 {
       
   443     GraphicsContext* c = drawingContext();
       
   444     if (!c)
       
   445         return;
       
   446     if (!state().m_invertibleCTM)
       
   447         return;
       
   448 
       
   449     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | 
       
   450         !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
       
   451         return;
       
   452 
       
   453     AffineTransform transform(m11, m12, m21, m22, dx, dy);
       
   454     AffineTransform newTransform = transform * state().m_transform;
       
   455     if (!newTransform.isInvertible()) {
       
   456         state().m_invertibleCTM = false;
       
   457         return;
       
   458     }
       
   459 
       
   460     state().m_transform = newTransform;
       
   461     c->concatCTM(transform);
       
   462     m_path.transform(transform.inverse());
       
   463 }
       
   464 
       
   465 void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
       
   466 {
       
   467     GraphicsContext* c = drawingContext();
       
   468     if (!c)
       
   469         return;
       
   470     
       
   471     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | 
       
   472         !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
       
   473         return;
       
   474 
       
   475     AffineTransform ctm = state().m_transform;
       
   476     if (!ctm.isInvertible())
       
   477         return;
       
   478     c->concatCTM(c->getCTM().inverse());
       
   479     c->concatCTM(canvas()->baseTransform());
       
   480     state().m_transform.multiply(ctm.inverse());
       
   481     m_path.transform(ctm);
       
   482 
       
   483     state().m_invertibleCTM = true;
       
   484     transform(m11, m12, m21, m22, dx, dy);
       
   485 }
       
   486 
       
   487 void CanvasRenderingContext2D::setStrokeColor(const String& color)
       
   488 {
       
   489     if (color == state().m_unparsedStrokeColor)
       
   490         return;
       
   491     setStrokeStyle(CanvasStyle::create(color));
       
   492     state().m_unparsedStrokeColor = color;
       
   493 }
       
   494 
       
   495 void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
       
   496 {
       
   497     setStrokeStyle(CanvasStyle::create(grayLevel, 1));
       
   498 }
       
   499 
       
   500 void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
       
   501 {
       
   502     setStrokeStyle(CanvasStyle::create(color, alpha));
       
   503 }
       
   504 
       
   505 void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
       
   506 {
       
   507     setStrokeStyle(CanvasStyle::create(grayLevel, alpha));
       
   508 }
       
   509 
       
   510 void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
       
   511 {
       
   512     setStrokeStyle(CanvasStyle::create(r, g, b, a));
       
   513 }
       
   514 
       
   515 void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
       
   516 {
       
   517     setStrokeStyle(CanvasStyle::create(c, m, y, k, a));
       
   518 }
       
   519 
       
   520 void CanvasRenderingContext2D::setFillColor(const String& color)
       
   521 {
       
   522     if (color == state().m_unparsedFillColor)
       
   523         return;
       
   524     setFillStyle(CanvasStyle::create(color));
       
   525     state().m_unparsedFillColor = color;
       
   526 }
       
   527 
       
   528 void CanvasRenderingContext2D::setFillColor(float grayLevel)
       
   529 {
       
   530     setFillStyle(CanvasStyle::create(grayLevel, 1));
       
   531 }
       
   532 
       
   533 void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
       
   534 {
       
   535     setFillStyle(CanvasStyle::create(color, alpha));
       
   536 }
       
   537 
       
   538 void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
       
   539 {
       
   540     setFillStyle(CanvasStyle::create(grayLevel, alpha));
       
   541 }
       
   542 
       
   543 void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
       
   544 {
       
   545     setFillStyle(CanvasStyle::create(r, g, b, a));
       
   546 }
       
   547 
       
   548 void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
       
   549 {
       
   550     setFillStyle(CanvasStyle::create(c, m, y, k, a));
       
   551 }
       
   552 
       
   553 void CanvasRenderingContext2D::beginPath()
       
   554 {
       
   555     m_path.clear();
       
   556 }
       
   557 
       
   558 void CanvasRenderingContext2D::closePath()
       
   559 {
       
   560     if (m_path.isEmpty())
       
   561         return;
       
   562 
       
   563     FloatRect boundRect = m_path.boundingRect();
       
   564     if (boundRect.width() || boundRect.height())
       
   565         m_path.closeSubpath();
       
   566 }
       
   567 
       
   568 void CanvasRenderingContext2D::moveTo(float x, float y)
       
   569 {
       
   570     if (!isfinite(x) | !isfinite(y))
       
   571         return;
       
   572     if (!state().m_invertibleCTM)
       
   573         return;
       
   574     m_path.moveTo(FloatPoint(x, y));
       
   575 }
       
   576 
       
   577 void CanvasRenderingContext2D::lineTo(float x, float y)
       
   578 {
       
   579     if (!isfinite(x) | !isfinite(y))
       
   580         return;
       
   581     if (!state().m_invertibleCTM)
       
   582         return;
       
   583 
       
   584     FloatPoint p1 = FloatPoint(x, y);
       
   585     if (!m_path.hasCurrentPoint())
       
   586         m_path.moveTo(p1);
       
   587     else if (p1 != m_path.currentPoint())
       
   588         m_path.addLineTo(FloatPoint(x, y));
       
   589 }
       
   590 
       
   591 void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y)
       
   592 {
       
   593     if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
       
   594         return;
       
   595     if (!state().m_invertibleCTM)
       
   596         return;
       
   597     if (!m_path.hasCurrentPoint())
       
   598         m_path.moveTo(FloatPoint(cpx, cpy));
       
   599 
       
   600     FloatPoint p1 = FloatPoint(x, y);
       
   601     if (p1 != m_path.currentPoint())
       
   602         m_path.addQuadCurveTo(FloatPoint(cpx, cpy), p1);
       
   603 }
       
   604 
       
   605 void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
       
   606 {
       
   607     if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
       
   608         return;
       
   609     if (!state().m_invertibleCTM)
       
   610         return;
       
   611     if (!m_path.hasCurrentPoint())
       
   612         m_path.moveTo(FloatPoint(cp1x, cp1y));
       
   613 
       
   614     FloatPoint p1 = FloatPoint(x, y);
       
   615     if (p1 != m_path.currentPoint())
       
   616         m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), p1);
       
   617 }
       
   618 
       
   619 void CanvasRenderingContext2D::arcTo(float x1, float y1, float x2, float y2, float r, ExceptionCode& ec)
       
   620 {
       
   621     ec = 0;
       
   622     if (!isfinite(x1) | !isfinite(y1) | !isfinite(x2) | !isfinite(y2) | !isfinite(r))
       
   623         return;
       
   624     
       
   625     if (r < 0) {
       
   626         ec = INDEX_SIZE_ERR;
       
   627         return;
       
   628     }
       
   629     
       
   630     if (!state().m_invertibleCTM)
       
   631         return;
       
   632     
       
   633     FloatPoint p1 = FloatPoint(x1, y1);
       
   634     FloatPoint p2 = FloatPoint(x2, y2);
       
   635 
       
   636     if (!m_path.hasCurrentPoint())
       
   637         m_path.moveTo(p1);
       
   638     else if (p1 == m_path.currentPoint() || p1 == p2 || !r)
       
   639         lineTo(x1, y1);
       
   640     else
       
   641         m_path.addArcTo(p1, p2, r);
       
   642 }
       
   643 
       
   644 void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
       
   645 {
       
   646     ec = 0;
       
   647     if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea))
       
   648         return;
       
   649     
       
   650     if (r < 0) {
       
   651         ec = INDEX_SIZE_ERR;
       
   652         return;
       
   653     }
       
   654 
       
   655     if (sa == ea)
       
   656         return;
       
   657 
       
   658     if (!state().m_invertibleCTM)
       
   659         return;
       
   660     m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
       
   661 }
       
   662     
       
   663 static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
       
   664 {
       
   665     if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
       
   666         return false;
       
   667 
       
   668     if (!width && !height)
       
   669         return false;
       
   670 
       
   671     if (width < 0) {
       
   672         width = -width;
       
   673         x -= width;
       
   674     }
       
   675     
       
   676     if (height < 0) {
       
   677         height = -height;
       
   678         y -= height;
       
   679     }
       
   680     
       
   681     return true;
       
   682 }
       
   683 
       
   684 void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
       
   685 {
       
   686     if (!state().m_invertibleCTM)
       
   687         return;
       
   688 
       
   689     if (!isfinite(x) || !isfinite(y) || !isfinite(width) || !isfinite(height))
       
   690         return;
       
   691 
       
   692     if (!width && !height) {
       
   693         m_path.moveTo(FloatPoint(x, y));
       
   694         return;
       
   695     }
       
   696 
       
   697     if (width < 0) {
       
   698         width = -width;
       
   699         x -= width;
       
   700     }
       
   701 
       
   702     if (height < 0) {
       
   703         height = -height;
       
   704         y -= height;
       
   705     }
       
   706 
       
   707     m_path.addRect(FloatRect(x, y, width, height));
       
   708 }
       
   709 
       
   710 #if ENABLE(DASHBOARD_SUPPORT)
       
   711 void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
       
   712 {
       
   713     if (m_usesDashboardCompatibilityMode)
       
   714         m_path.clear();
       
   715 }
       
   716 #endif
       
   717 
       
   718 void CanvasRenderingContext2D::fill()
       
   719 {
       
   720     GraphicsContext* c = drawingContext();
       
   721     if (!c)
       
   722         return;
       
   723     if (!state().m_invertibleCTM)
       
   724         return;
       
   725 
       
   726     if (!m_path.isEmpty()) {
       
   727         c->beginPath();
       
   728         c->addPath(m_path);
       
   729         willDraw(m_path.boundingRect());
       
   730         c->fillPath();
       
   731     }
       
   732 
       
   733 #if ENABLE(DASHBOARD_SUPPORT)
       
   734     clearPathForDashboardBackwardCompatibilityMode();
       
   735 #endif
       
   736 }
       
   737 
       
   738 void CanvasRenderingContext2D::stroke()
       
   739 {
       
   740     GraphicsContext* c = drawingContext();
       
   741     if (!c)
       
   742         return;
       
   743     if (!state().m_invertibleCTM)
       
   744         return;
       
   745 
       
   746     if (!m_path.isEmpty()) {
       
   747         c->beginPath();
       
   748         c->addPath(m_path);
       
   749 
       
   750         CanvasStrokeStyleApplier strokeApplier(this);
       
   751         FloatRect boundingRect = m_path.strokeBoundingRect(&strokeApplier);
       
   752         willDraw(boundingRect);
       
   753 
       
   754         c->strokePath();
       
   755     }
       
   756 
       
   757 #if ENABLE(DASHBOARD_SUPPORT)
       
   758     clearPathForDashboardBackwardCompatibilityMode();
       
   759 #endif
       
   760 }
       
   761 
       
   762 void CanvasRenderingContext2D::clip()
       
   763 {
       
   764     GraphicsContext* c = drawingContext();
       
   765     if (!c)
       
   766         return;
       
   767     if (!state().m_invertibleCTM)
       
   768         return;
       
   769     c->canvasClip(m_path);
       
   770 #if ENABLE(DASHBOARD_SUPPORT)
       
   771     clearPathForDashboardBackwardCompatibilityMode();
       
   772 #endif
       
   773 }
       
   774 
       
   775 bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
       
   776 {
       
   777     GraphicsContext* c = drawingContext();
       
   778     if (!c)
       
   779         return false;
       
   780     if (!state().m_invertibleCTM)
       
   781         return false;
       
   782 
       
   783     FloatPoint point(x, y);
       
   784     AffineTransform ctm = state().m_transform;
       
   785     FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
       
   786     return m_path.contains(transformedPoint);
       
   787 }
       
   788 
       
   789 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
       
   790 {
       
   791     if (!validateRectForCanvas(x, y, width, height))
       
   792         return;
       
   793     GraphicsContext* c = drawingContext();
       
   794     if (!c)
       
   795         return;
       
   796     if (!state().m_invertibleCTM)
       
   797         return;
       
   798     FloatRect rect(x, y, width, height);
       
   799     willDraw(rect);
       
   800     c->clearRect(rect);
       
   801 }
       
   802 
       
   803 void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
       
   804 {
       
   805     if (!validateRectForCanvas(x, y, width, height))
       
   806         return;
       
   807 
       
   808     GraphicsContext* c = drawingContext();
       
   809     if (!c)
       
   810         return;
       
   811     if (!state().m_invertibleCTM)
       
   812         return;
       
   813 
       
   814     // from the HTML5 Canvas spec:
       
   815     // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
       
   816     // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
       
   817     Gradient* gradient = c->fillGradient();
       
   818     if (gradient && gradient->isZeroSize())
       
   819         return;
       
   820 
       
   821     FloatRect rect(x, y, width, height);
       
   822     willDraw(rect);
       
   823 
       
   824     c->fillRect(rect);
       
   825 }
       
   826 
       
   827 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
       
   828 {
       
   829     if (!validateRectForCanvas(x, y, width, height))
       
   830         return;
       
   831     strokeRect(x, y, width, height, state().m_lineWidth);
       
   832 }
       
   833 
       
   834 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
       
   835 {
       
   836     if (!validateRectForCanvas(x, y, width, height))
       
   837         return;
       
   838     
       
   839     if (!(lineWidth >= 0))
       
   840         return;
       
   841 
       
   842     GraphicsContext* c = drawingContext();
       
   843     if (!c)
       
   844         return;
       
   845     if (!state().m_invertibleCTM)
       
   846         return;
       
   847 
       
   848     FloatRect rect(x, y, width, height);
       
   849 
       
   850     FloatRect boundingRect = rect;
       
   851     boundingRect.inflate(lineWidth / 2);
       
   852     willDraw(boundingRect);
       
   853 
       
   854     c->strokeRect(rect, lineWidth);
       
   855 }
       
   856 
       
   857 #if PLATFORM(CG)
       
   858 static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height)
       
   859 {
       
   860     // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated
       
   861     // to the desired integer.
       
   862     static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
       
   863     if (width > 0)
       
   864         width += extraShadowOffset;
       
   865     else if (width < 0)
       
   866         width -= extraShadowOffset;
       
   867 
       
   868     if (height > 0)
       
   869         height += extraShadowOffset;
       
   870     else if (height < 0)
       
   871         height -= extraShadowOffset;
       
   872 
       
   873     return CGSizeMake(width, height);
       
   874 }
       
   875 #endif
       
   876 
       
   877 void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
       
   878 {
       
   879     state().m_shadowOffset = FloatSize(width, height);
       
   880     state().m_shadowBlur = blur;
       
   881     state().m_shadowColor = Color::transparent;
       
   882     applyShadow();
       
   883 }
       
   884 
       
   885 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
       
   886 {
       
   887     if (!CSSParser::parseColor(state().m_shadowColor, color))
       
   888         return;
       
   889 
       
   890     state().m_shadowOffset = FloatSize(width, height);
       
   891     state().m_shadowBlur = blur;
       
   892     applyShadow();
       
   893 }
       
   894 
       
   895 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
       
   896 {
       
   897     state().m_shadowOffset = FloatSize(width, height);
       
   898     state().m_shadowBlur = blur;
       
   899     state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f);
       
   900 
       
   901     GraphicsContext* c = drawingContext();
       
   902     if (!c)
       
   903         return;
       
   904 
       
   905     c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace);
       
   906 }
       
   907 
       
   908 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
       
   909 {
       
   910     RGBA32 rgba;
       
   911 
       
   912     if (!CSSParser::parseColor(rgba, color))
       
   913         return;
       
   914 
       
   915     state().m_shadowColor = colorWithOverrideAlpha(rgba, alpha);
       
   916     state().m_shadowOffset = FloatSize(width, height);
       
   917     state().m_shadowBlur = blur;
       
   918 
       
   919     GraphicsContext* c = drawingContext();
       
   920     if (!c)
       
   921         return;
       
   922 
       
   923     c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace);
       
   924 }
       
   925 
       
   926 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
       
   927 {
       
   928     state().m_shadowOffset = FloatSize(width, height);
       
   929     state().m_shadowBlur = blur;
       
   930     state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha);
       
   931 
       
   932     GraphicsContext* c = drawingContext();
       
   933     if (!c)
       
   934         return;
       
   935 
       
   936     c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace);
       
   937 }
       
   938 
       
   939 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
       
   940 {
       
   941     state().m_shadowOffset = FloatSize(width, height);
       
   942     state().m_shadowBlur = blur;
       
   943     state().m_shadowColor = makeRGBA32FromFloats(r, g, b, a);
       
   944 
       
   945     GraphicsContext* c = drawingContext();
       
   946     if (!c)
       
   947         return;
       
   948 
       
   949     c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace);
       
   950 }
       
   951 
       
   952 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
       
   953 {
       
   954     state().m_shadowOffset = FloatSize(width, height);
       
   955     state().m_shadowBlur = blur;
       
   956     state().m_shadowColor = makeRGBAFromCMYKA(c, m, y, k, a);
       
   957 
       
   958     GraphicsContext* dc = drawingContext();
       
   959     if (!dc)
       
   960         return;
       
   961 #if PLATFORM(CG)
       
   962     const CGFloat components[5] = { c, m, y, k, a };
       
   963     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK();
       
   964     CGColorRef shadowColor = CGColorCreate(colorSpace, components);
       
   965     CGColorSpaceRelease(colorSpace);
       
   966     CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
       
   967     CGColorRelease(shadowColor);
       
   968 #else
       
   969     dc->setShadow(IntSize(width, -height), blur, state().m_shadowColor, DeviceColorSpace);
       
   970 #endif
       
   971 }
       
   972 
       
   973 void CanvasRenderingContext2D::clearShadow()
       
   974 {
       
   975     state().m_shadowOffset = FloatSize();
       
   976     state().m_shadowBlur = 0;
       
   977     state().m_shadowColor = Color::transparent;
       
   978     applyShadow();
       
   979 }
       
   980 
       
   981 void CanvasRenderingContext2D::applyShadow()
       
   982 {
       
   983     GraphicsContext* c = drawingContext();
       
   984     if (!c)
       
   985         return;
       
   986 
       
   987     float width = state().m_shadowOffset.width();
       
   988     float height = state().m_shadowOffset.height();
       
   989     c->setShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace);
       
   990 }
       
   991 
       
   992 static IntSize size(HTMLImageElement* image)
       
   993 {
       
   994     if (CachedImage* cachedImage = image->cachedImage())
       
   995         return cachedImage->imageSize(1.0f); // FIXME: Not sure about this.
       
   996     return IntSize();
       
   997 }
       
   998 
       
   999 #if ENABLE(VIDEO)
       
  1000 static IntSize size(HTMLVideoElement* video)
       
  1001 {
       
  1002     if (MediaPlayer* player = video->player())
       
  1003         return player->naturalSize();
       
  1004     return IntSize();
       
  1005 }
       
  1006 #endif
       
  1007 
       
  1008 static inline FloatRect normalizeRect(const FloatRect& rect)
       
  1009 {
       
  1010     return FloatRect(min(rect.x(), rect.right()),
       
  1011         min(rect.y(), rect.bottom()),
       
  1012         max(rect.width(), -rect.width()),
       
  1013         max(rect.height(), -rect.height()));
       
  1014 }
       
  1015 
       
  1016 void CanvasRenderingContext2D::checkOrigin(const KURL& url)
       
  1017 {
       
  1018     if (m_cleanOrigins.contains(url.string()))
       
  1019         return;
       
  1020 
       
  1021     if (canvas()->securityOrigin().taintsCanvas(url))
       
  1022         canvas()->setOriginTainted();
       
  1023     else
       
  1024         m_cleanOrigins.add(url.string());
       
  1025 }
       
  1026 
       
  1027 void CanvasRenderingContext2D::checkOrigin(const String& url)
       
  1028 {
       
  1029     if (m_cleanOrigins.contains(url))
       
  1030         return;
       
  1031 
       
  1032     checkOrigin(KURL(KURL(), url));
       
  1033 }
       
  1034 
       
  1035 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, ExceptionCode& ec)
       
  1036 {
       
  1037     if (!image) {
       
  1038         ec = TYPE_MISMATCH_ERR;
       
  1039         return;
       
  1040     }
       
  1041     IntSize s = size(image);
       
  1042     drawImage(image, x, y, s.width(), s.height(), ec);
       
  1043 }
       
  1044 
       
  1045 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
       
  1046     float x, float y, float width, float height, ExceptionCode& ec)
       
  1047 {
       
  1048     if (!image) {
       
  1049         ec = TYPE_MISMATCH_ERR;
       
  1050         return;
       
  1051     }
       
  1052     IntSize s = size(image);
       
  1053     drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
       
  1054 }
       
  1055 
       
  1056 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
       
  1057     float sx, float sy, float sw, float sh,
       
  1058     float dx, float dy, float dw, float dh, ExceptionCode& ec)
       
  1059 {
       
  1060     if (!image) {
       
  1061         ec = TYPE_MISMATCH_ERR;
       
  1062         return;
       
  1063     }
       
  1064     drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
       
  1065 }
       
  1066 
       
  1067 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect,
       
  1068     ExceptionCode& ec)
       
  1069 {
       
  1070     if (!image) {
       
  1071         ec = TYPE_MISMATCH_ERR;
       
  1072         return;
       
  1073     }
       
  1074 
       
  1075     ec = 0;
       
  1076 
       
  1077     if (!isfinite(dstRect.x()) || !isfinite(dstRect.y()) || !isfinite(dstRect.width()) || !isfinite(dstRect.height())
       
  1078         || !isfinite(srcRect.x()) || !isfinite(srcRect.y()) || !isfinite(srcRect.width()) || !isfinite(srcRect.height()))
       
  1079         return;
       
  1080 
       
  1081     if (!image->complete())
       
  1082         return;
       
  1083 
       
  1084     FloatRect imageRect = FloatRect(FloatPoint(), size(image));
       
  1085     if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
       
  1086         ec = INDEX_SIZE_ERR;
       
  1087         return;
       
  1088     }
       
  1089 
       
  1090     if (!dstRect.width() || !dstRect.height())
       
  1091         return;
       
  1092 
       
  1093     GraphicsContext* c = drawingContext();
       
  1094     if (!c)
       
  1095         return;
       
  1096     if (!state().m_invertibleCTM)
       
  1097         return;
       
  1098 
       
  1099     CachedImage* cachedImage = image->cachedImage();
       
  1100     if (!cachedImage)
       
  1101         return;
       
  1102 
       
  1103     if (canvas()->originClean())
       
  1104         checkOrigin(cachedImage->response().url());
       
  1105 
       
  1106     if (canvas()->originClean() && !cachedImage->image()->hasSingleSecurityOrigin())
       
  1107         canvas()->setOriginTainted();
       
  1108 
       
  1109     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
       
  1110     FloatRect destRect = c->roundToDevicePixels(dstRect);
       
  1111     willDraw(destRect);
       
  1112     c->drawImage(cachedImage->image(), DeviceColorSpace, destRect, sourceRect, state().m_globalComposite);
       
  1113 }
       
  1114 
       
  1115 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y, ExceptionCode& ec)
       
  1116 {
       
  1117     if (!canvas) {
       
  1118         ec = TYPE_MISMATCH_ERR;
       
  1119         return;
       
  1120     }
       
  1121     drawImage(canvas, x, y, canvas->width(), canvas->height(), ec);
       
  1122 }
       
  1123 
       
  1124 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
       
  1125     float x, float y, float width, float height, ExceptionCode& ec)
       
  1126 {
       
  1127     if (!canvas) {
       
  1128         ec = TYPE_MISMATCH_ERR;
       
  1129         return;
       
  1130     }
       
  1131     drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec);
       
  1132 }
       
  1133 
       
  1134 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
       
  1135     float sx, float sy, float sw, float sh,
       
  1136     float dx, float dy, float dw, float dh, ExceptionCode& ec)
       
  1137 {
       
  1138     drawImage(canvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
       
  1139 }
       
  1140 
       
  1141 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const FloatRect& srcRect,
       
  1142     const FloatRect& dstRect, ExceptionCode& ec)
       
  1143 {
       
  1144     if (!sourceCanvas) {
       
  1145         ec = TYPE_MISMATCH_ERR;
       
  1146         return;
       
  1147     }
       
  1148 
       
  1149     FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size());
       
  1150 
       
  1151     if (!srcCanvasRect.width() || !srcCanvasRect.height()) {
       
  1152         ec = INVALID_STATE_ERR;
       
  1153         return;
       
  1154     }
       
  1155 
       
  1156     if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
       
  1157         ec = INDEX_SIZE_ERR;
       
  1158         return;
       
  1159     }
       
  1160 
       
  1161     ec = 0;
       
  1162 
       
  1163     if (!dstRect.width() || !dstRect.height())
       
  1164         return;
       
  1165 
       
  1166     GraphicsContext* c = drawingContext();
       
  1167     if (!c)
       
  1168         return;
       
  1169     if (!state().m_invertibleCTM)
       
  1170         return;
       
  1171         
       
  1172     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
       
  1173     FloatRect destRect = c->roundToDevicePixels(dstRect);
       
  1174         
       
  1175     // FIXME: Do this through platform-independent GraphicsContext API.
       
  1176     ImageBuffer* buffer = sourceCanvas->buffer();
       
  1177     if (!buffer)
       
  1178         return;
       
  1179 
       
  1180     if (!sourceCanvas->originClean())
       
  1181         canvas()->setOriginTainted();
       
  1182 
       
  1183     sourceCanvas->makeRenderingResultsAvailable();
       
  1184 
       
  1185     c->drawImage(buffer->image(), DeviceColorSpace, destRect, sourceRect, state().m_globalComposite);
       
  1186     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.
       
  1187                         // FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this.
       
  1188 }
       
  1189 
       
  1190 #if ENABLE(VIDEO)
       
  1191 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, ExceptionCode& ec)
       
  1192 {
       
  1193     if (!video) {
       
  1194         ec = TYPE_MISMATCH_ERR;
       
  1195         return;
       
  1196     }
       
  1197     IntSize s = size(video);
       
  1198     drawImage(video, x, y, s.width(), s.height(), ec);
       
  1199 }
       
  1200 
       
  1201 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
       
  1202                                          float x, float y, float width, float height, ExceptionCode& ec)
       
  1203 {
       
  1204     if (!video) {
       
  1205         ec = TYPE_MISMATCH_ERR;
       
  1206         return;
       
  1207     }
       
  1208     IntSize s = size(video);
       
  1209     drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
       
  1210 }
       
  1211 
       
  1212 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
       
  1213     float sx, float sy, float sw, float sh,
       
  1214     float dx, float dy, float dw, float dh, ExceptionCode& ec)
       
  1215 {
       
  1216     drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
       
  1217 }
       
  1218 
       
  1219 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect,
       
  1220                                          ExceptionCode& ec)
       
  1221 {
       
  1222     if (!video) {
       
  1223         ec = TYPE_MISMATCH_ERR;
       
  1224         return;
       
  1225     }
       
  1226     
       
  1227     ec = 0;
       
  1228 
       
  1229     if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readyState() == HTMLMediaElement::HAVE_METADATA)
       
  1230         return;
       
  1231 
       
  1232     FloatRect videoRect = FloatRect(FloatPoint(), size(video));
       
  1233     if (!videoRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
       
  1234         ec = INDEX_SIZE_ERR;
       
  1235         return;
       
  1236     }
       
  1237     
       
  1238     if (!dstRect.width() || !dstRect.height())
       
  1239         return;
       
  1240     
       
  1241     GraphicsContext* c = drawingContext();
       
  1242     if (!c)
       
  1243         return;
       
  1244     if (!state().m_invertibleCTM)
       
  1245         return;
       
  1246 
       
  1247     if (canvas()->originClean())
       
  1248         checkOrigin(video->currentSrc());
       
  1249 
       
  1250     if (canvas()->originClean() && !video->hasSingleSecurityOrigin())
       
  1251         canvas()->setOriginTainted();
       
  1252 
       
  1253     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
       
  1254     FloatRect destRect = c->roundToDevicePixels(dstRect);
       
  1255     willDraw(destRect);
       
  1256 
       
  1257     c->save();
       
  1258     c->clip(destRect);
       
  1259     c->translate(destRect.x(), destRect.y());
       
  1260     c->scale(FloatSize(destRect.width()/sourceRect.width(), destRect.height()/sourceRect.height()));
       
  1261     c->translate(-sourceRect.x(), -sourceRect.y());
       
  1262     video->paintCurrentFrameInContext(c, IntRect(IntPoint(), size(video)));
       
  1263     c->restore();
       
  1264 }
       
  1265 #endif
       
  1266 
       
  1267 // FIXME: Why isn't this just another overload of drawImage? Why have a different name?
       
  1268 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
       
  1269     float sx, float sy, float sw, float sh,
       
  1270     float dx, float dy, float dw, float dh,
       
  1271     const String& compositeOperation)
       
  1272 {
       
  1273     if (!image)
       
  1274         return;
       
  1275 
       
  1276     CachedImage* cachedImage = image->cachedImage();
       
  1277     if (!cachedImage)
       
  1278         return;
       
  1279 
       
  1280     if (canvas()->originClean())
       
  1281         checkOrigin(cachedImage->response().url());
       
  1282 
       
  1283     if (canvas()->originClean() && !cachedImage->image()->hasSingleSecurityOrigin())
       
  1284         canvas()->setOriginTainted();
       
  1285 
       
  1286     GraphicsContext* c = drawingContext();
       
  1287     if (!c)
       
  1288         return;
       
  1289     if (!state().m_invertibleCTM)
       
  1290         return;
       
  1291 
       
  1292     CompositeOperator op;
       
  1293     if (!parseCompositeOperator(compositeOperation, op))
       
  1294         op = CompositeSourceOver;
       
  1295 
       
  1296     FloatRect destRect = FloatRect(dx, dy, dw, dh);
       
  1297     willDraw(destRect);
       
  1298     c->drawImage(cachedImage->image(), DeviceColorSpace, destRect, FloatRect(sx, sy, sw, sh), op);
       
  1299 }
       
  1300 
       
  1301 void CanvasRenderingContext2D::setAlpha(float alpha)
       
  1302 {
       
  1303     setGlobalAlpha(alpha);
       
  1304 }
       
  1305 
       
  1306 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
       
  1307 {
       
  1308     setGlobalCompositeOperation(operation);
       
  1309 }
       
  1310 
       
  1311 void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient* gradient) const
       
  1312 {
       
  1313 #if ENABLE(DASHBOARD_SUPPORT)
       
  1314     if (m_usesDashboardCompatibilityMode)
       
  1315         gradient->setDashboardCompatibilityMode();
       
  1316 #else
       
  1317     UNUSED_PARAM(gradient);
       
  1318 #endif
       
  1319 }
       
  1320 
       
  1321 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec)
       
  1322 {
       
  1323     if (!isfinite(x0) || !isfinite(y0) || !isfinite(x1) || !isfinite(y1)) {
       
  1324         ec = NOT_SUPPORTED_ERR;
       
  1325         return 0;
       
  1326     }
       
  1327 
       
  1328     PassRefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
       
  1329     prepareGradientForDashboard(gradient.get());
       
  1330     return gradient;
       
  1331 }
       
  1332 
       
  1333 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec)
       
  1334 {
       
  1335     if (!isfinite(x0) || !isfinite(y0) || !isfinite(r0) || 
       
  1336         !isfinite(x1) || !isfinite(y1) || !isfinite(r1)) {
       
  1337         ec = NOT_SUPPORTED_ERR;
       
  1338         return 0;
       
  1339     }
       
  1340     PassRefPtr<CanvasGradient> gradient =  CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
       
  1341     prepareGradientForDashboard(gradient.get());
       
  1342     return gradient;
       
  1343 }
       
  1344 
       
  1345 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image,
       
  1346     const String& repetitionType, ExceptionCode& ec)
       
  1347 {
       
  1348     if (!image) {
       
  1349         ec = TYPE_MISMATCH_ERR;
       
  1350         return 0;
       
  1351     }
       
  1352     bool repeatX, repeatY;
       
  1353     ec = 0;
       
  1354     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
       
  1355     if (ec)
       
  1356         return 0;
       
  1357 
       
  1358     if (!image->complete())
       
  1359         return 0;
       
  1360 
       
  1361     CachedImage* cachedImage = image->cachedImage();
       
  1362     if (!cachedImage || !image->cachedImage()->image())
       
  1363         return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
       
  1364 
       
  1365     bool originClean = !canvas()->securityOrigin().taintsCanvas(KURL(KURL(), cachedImage->url())) && cachedImage->image()->hasSingleSecurityOrigin();
       
  1366     return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean);
       
  1367 }
       
  1368 
       
  1369 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
       
  1370     const String& repetitionType, ExceptionCode& ec)
       
  1371 {
       
  1372     if (!canvas) {
       
  1373         ec = TYPE_MISMATCH_ERR;
       
  1374         return 0;
       
  1375     }
       
  1376     if (!canvas->width() || !canvas->height()) {
       
  1377         ec = INVALID_STATE_ERR;
       
  1378         return 0;
       
  1379     }
       
  1380     
       
  1381     bool repeatX, repeatY;
       
  1382     ec = 0;
       
  1383     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
       
  1384     if (ec)
       
  1385         return 0;
       
  1386     return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean());
       
  1387 }
       
  1388 
       
  1389 void CanvasRenderingContext2D::willDraw(const FloatRect& r, unsigned options)
       
  1390 {
       
  1391     GraphicsContext* c = drawingContext();
       
  1392     if (!c)
       
  1393         return;
       
  1394     if (!state().m_invertibleCTM)
       
  1395         return;
       
  1396 
       
  1397     FloatRect dirtyRect = r;
       
  1398     if (options & CanvasWillDrawApplyTransform) {
       
  1399         AffineTransform ctm = state().m_transform;
       
  1400         dirtyRect = ctm.mapRect(r);
       
  1401     }
       
  1402     
       
  1403     if (options & CanvasWillDrawApplyShadow && alphaChannel(state().m_shadowColor)) {
       
  1404         // The shadow gets applied after transformation
       
  1405         FloatRect shadowRect(dirtyRect);
       
  1406         shadowRect.move(state().m_shadowOffset);
       
  1407         shadowRect.inflate(state().m_shadowBlur);
       
  1408         dirtyRect.unite(shadowRect);
       
  1409     }
       
  1410     
       
  1411     if (options & CanvasWillDrawApplyClip) {
       
  1412         // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
       
  1413         // back out of the GraphicsContext, so to take clip into account for incremental painting,
       
  1414         // we'd have to keep the clip path around.
       
  1415     }
       
  1416     
       
  1417     canvas()->willDraw(dirtyRect);
       
  1418 }
       
  1419 
       
  1420 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
       
  1421 {
       
  1422     return canvas()->drawingContext();
       
  1423 }
       
  1424 
       
  1425 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
       
  1426 {
       
  1427     RefPtr<ImageData> data = ImageData::create(size.width(), size.height());
       
  1428     memset(data->data()->data()->data(), 0, data->data()->data()->length());
       
  1429     return data.get();
       
  1430 }
       
  1431 
       
  1432 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtr<ImageData> imageData, ExceptionCode& ec) const
       
  1433 {
       
  1434     if (!imageData) {
       
  1435         ec = NOT_SUPPORTED_ERR;
       
  1436         return 0;
       
  1437     }
       
  1438 
       
  1439     IntSize size(imageData->width(), imageData->height());
       
  1440     return createEmptyImageData(size);
       
  1441 }
       
  1442 
       
  1443 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionCode& ec) const
       
  1444 {
       
  1445     ec = 0;
       
  1446     if (!sw || !sh) {
       
  1447         ec = INDEX_SIZE_ERR;
       
  1448         return 0;
       
  1449     }
       
  1450     if (!isfinite(sw) || !isfinite(sh)) {
       
  1451         ec = NOT_SUPPORTED_ERR;
       
  1452         return 0;
       
  1453     }
       
  1454 
       
  1455     FloatSize unscaledSize(fabs(sw), fabs(sh));
       
  1456     IntSize scaledSize = canvas()->convertLogicalToDevice(unscaledSize);
       
  1457     if (scaledSize.width() < 1)
       
  1458         scaledSize.setWidth(1);
       
  1459     if (scaledSize.height() < 1)
       
  1460         scaledSize.setHeight(1);
       
  1461     
       
  1462     return createEmptyImageData(scaledSize);
       
  1463 }
       
  1464 
       
  1465 PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
       
  1466 {
       
  1467     if (!canvas()->originClean()) {
       
  1468         ec = SECURITY_ERR;
       
  1469         return 0;
       
  1470     }
       
  1471     if (!sw || !sh) {
       
  1472         ec = INDEX_SIZE_ERR;
       
  1473         return 0;
       
  1474     }
       
  1475     if (!isfinite(sx) || !isfinite(sy) || !isfinite(sw) || !isfinite(sh)) {
       
  1476         ec = NOT_SUPPORTED_ERR;
       
  1477         return 0;
       
  1478     }
       
  1479 
       
  1480     FloatRect unscaledRect(sx, sy, sw, sh);
       
  1481     IntRect scaledRect = canvas()->convertLogicalToDevice(unscaledRect);
       
  1482     if (scaledRect.width() < 1)
       
  1483         scaledRect.setWidth(1);
       
  1484     if (scaledRect.height() < 1)
       
  1485         scaledRect.setHeight(1);
       
  1486     ImageBuffer* buffer = canvas() ? canvas()->buffer() : 0;
       
  1487     if (!buffer)
       
  1488         return createEmptyImageData(scaledRect.size());
       
  1489     return buffer->getUnmultipliedImageData(scaledRect);
       
  1490 }
       
  1491 
       
  1492 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
       
  1493 {
       
  1494     if (!data) {
       
  1495         ec = TYPE_MISMATCH_ERR;
       
  1496         return;
       
  1497     }
       
  1498     putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
       
  1499 }
       
  1500 
       
  1501 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, 
       
  1502                                             float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
       
  1503 {
       
  1504     if (!data) {
       
  1505         ec = TYPE_MISMATCH_ERR;
       
  1506         return;
       
  1507     }
       
  1508     if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || 
       
  1509         !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
       
  1510         ec = NOT_SUPPORTED_ERR;
       
  1511         return;
       
  1512     }
       
  1513 
       
  1514     ImageBuffer* buffer = canvas()->buffer();
       
  1515     if (!buffer)
       
  1516         return;
       
  1517 
       
  1518     if (dirtyWidth < 0) {
       
  1519         dirtyX += dirtyWidth;
       
  1520         dirtyWidth = -dirtyWidth;
       
  1521     }
       
  1522 
       
  1523     if (dirtyHeight < 0) {
       
  1524         dirtyY += dirtyHeight;
       
  1525         dirtyHeight = -dirtyHeight;
       
  1526     }
       
  1527 
       
  1528     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
       
  1529     clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
       
  1530     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
       
  1531     IntRect sourceRect = enclosingIntRect(clipRect);
       
  1532     sourceRect.move(destOffset);
       
  1533     sourceRect.intersect(IntRect(IntPoint(), buffer->size()));
       
  1534     if (sourceRect.isEmpty())
       
  1535         return;
       
  1536     willDraw(sourceRect, 0);  // ignore transform, shadow and clip
       
  1537     sourceRect.move(-destOffset);
       
  1538     IntPoint destPoint(destOffset.width(), destOffset.height());
       
  1539     
       
  1540     buffer->putUnmultipliedImageData(data, sourceRect, destPoint);
       
  1541 }
       
  1542 
       
  1543 String CanvasRenderingContext2D::font() const
       
  1544 {
       
  1545     return state().m_unparsedFont;
       
  1546 }
       
  1547 
       
  1548 void CanvasRenderingContext2D::setFont(const String& newFont)
       
  1549 {
       
  1550     RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create();
       
  1551     CSSParser parser(!m_usesCSSCompatibilityParseMode);
       
  1552         
       
  1553     String declarationText("font: ");
       
  1554     declarationText += newFont;
       
  1555     parser.parseDeclaration(tempDecl.get(), declarationText);
       
  1556     if (!tempDecl->length())
       
  1557         return;
       
  1558             
       
  1559     // The parse succeeded.
       
  1560     state().m_unparsedFont = newFont;
       
  1561     
       
  1562     // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
       
  1563     // relative to the canvas.
       
  1564     RefPtr<RenderStyle> newStyle = RenderStyle::create();
       
  1565     if (RenderStyle* computedStyle = canvas()->computedStyle())
       
  1566         newStyle->setFontDescription(computedStyle->fontDescription());
       
  1567 
       
  1568     // Now map the font property into the style.
       
  1569     CSSStyleSelector* styleSelector = canvas()->styleSelector();
       
  1570     styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get());
       
  1571     
       
  1572     state().m_font = newStyle->font();
       
  1573     state().m_font.update(styleSelector->fontSelector());
       
  1574     state().m_realizedFont = true;
       
  1575 }
       
  1576 
       
  1577 void CanvasRenderingContext2D::updateFont()
       
  1578 {
       
  1579     if (!state().m_realizedFont)
       
  1580         return;
       
  1581 
       
  1582     const Font& font = state().m_font;
       
  1583     font.update(font.fontSelector());
       
  1584 }
       
  1585 
       
  1586 String CanvasRenderingContext2D::textAlign() const
       
  1587 {
       
  1588     return textAlignName(state().m_textAlign);
       
  1589 }
       
  1590 
       
  1591 void CanvasRenderingContext2D::setTextAlign(const String& s)
       
  1592 {
       
  1593     TextAlign align;
       
  1594     if (!parseTextAlign(s, align))
       
  1595         return;
       
  1596     state().m_textAlign = align;
       
  1597 }
       
  1598         
       
  1599 String CanvasRenderingContext2D::textBaseline() const
       
  1600 {
       
  1601     return textBaselineName(state().m_textBaseline);
       
  1602 }
       
  1603 
       
  1604 void CanvasRenderingContext2D::setTextBaseline(const String& s)
       
  1605 {
       
  1606     TextBaseline baseline;
       
  1607     if (!parseTextBaseline(s, baseline))
       
  1608         return;
       
  1609     state().m_textBaseline = baseline;
       
  1610 }
       
  1611 
       
  1612 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
       
  1613 {
       
  1614     drawTextInternal(text, x, y, true);
       
  1615 }
       
  1616 
       
  1617 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
       
  1618 {
       
  1619     drawTextInternal(text, x, y, true, maxWidth, true);
       
  1620 }
       
  1621 
       
  1622 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
       
  1623 {
       
  1624     drawTextInternal(text, x, y, false);
       
  1625 }
       
  1626 
       
  1627 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
       
  1628 {
       
  1629     drawTextInternal(text, x, y, false, maxWidth, true);
       
  1630 }
       
  1631 
       
  1632 PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
       
  1633 {
       
  1634     RefPtr<TextMetrics> metrics = TextMetrics::create();
       
  1635     metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
       
  1636     return metrics;
       
  1637 }
       
  1638 
       
  1639 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/)
       
  1640 {
       
  1641     GraphicsContext* c = drawingContext();
       
  1642     if (!c)
       
  1643         return;
       
  1644     if (!state().m_invertibleCTM)
       
  1645         return;
       
  1646     
       
  1647     const Font& font = accessFont();
       
  1648 
       
  1649     // FIXME: Handle maxWidth.
       
  1650     // FIXME: Need to turn off font smoothing.
       
  1651 
       
  1652     RenderStyle* computedStyle = canvas()->computedStyle();
       
  1653     bool rtl = computedStyle ? computedStyle->direction() == RTL : false;
       
  1654     bool override = computedStyle ? computedStyle->unicodeBidi() == Override : false;
       
  1655 
       
  1656     unsigned length = text.length();
       
  1657     const UChar* string = text.characters();
       
  1658     TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false);
       
  1659 
       
  1660     // Draw the item text at the correct point.
       
  1661     FloatPoint location(x, y);
       
  1662     switch (state().m_textBaseline) {
       
  1663         case TopTextBaseline:
       
  1664         case HangingTextBaseline:
       
  1665             location.setY(y + font.ascent());
       
  1666             break;
       
  1667         case BottomTextBaseline:
       
  1668         case IdeographicTextBaseline:
       
  1669             location.setY(y - font.descent());
       
  1670             break;
       
  1671         case MiddleTextBaseline:
       
  1672             location.setY(y - font.descent() + font.height() / 2);
       
  1673             break;
       
  1674         case AlphabeticTextBaseline:
       
  1675         default:
       
  1676              // Do nothing.
       
  1677             break;
       
  1678     }
       
  1679     
       
  1680     float width = font.width(TextRun(text, false, 0, 0, rtl, override));
       
  1681 
       
  1682     TextAlign align = state().m_textAlign;
       
  1683     if (align == StartTextAlign)
       
  1684          align = rtl ? RightTextAlign : LeftTextAlign;
       
  1685     else if (align == EndTextAlign)
       
  1686         align = rtl ? LeftTextAlign : RightTextAlign;
       
  1687     
       
  1688     switch (align) {
       
  1689         case CenterTextAlign:
       
  1690             location.setX(location.x() - width / 2);
       
  1691             break;
       
  1692         case RightTextAlign:
       
  1693             location.setX(location.x() - width);
       
  1694             break;
       
  1695         default:
       
  1696             break;
       
  1697     }
       
  1698     
       
  1699     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
       
  1700     FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(),
       
  1701                                    width + font.height(), font.lineSpacing());
       
  1702     if (!fill)
       
  1703         textRect.inflate(c->strokeThickness() / 2);
       
  1704 
       
  1705     if (fill)
       
  1706         canvas()->willDraw(textRect);
       
  1707     else {
       
  1708         // When stroking text, pointy miters can extend outside of textRect, so we
       
  1709         // punt and dirty the whole canvas.
       
  1710         canvas()->willDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
       
  1711     }
       
  1712     
       
  1713 #if PLATFORM(CG)
       
  1714     CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get();
       
  1715     if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
       
  1716         // FIXME: The rect is not big enough for miters on stroked text.
       
  1717         IntRect maskRect = enclosingIntRect(textRect);
       
  1718 
       
  1719         OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size());
       
  1720 
       
  1721         GraphicsContext* maskImageContext = maskImage->context();
       
  1722 
       
  1723         if (fill)
       
  1724             maskImageContext->setFillColor(Color::black, DeviceColorSpace);
       
  1725         else {
       
  1726             maskImageContext->setStrokeColor(Color::black, DeviceColorSpace);
       
  1727             maskImageContext->setStrokeThickness(c->strokeThickness());
       
  1728         }
       
  1729 
       
  1730         maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke);
       
  1731         maskImageContext->translate(-maskRect.x(), -maskRect.y());
       
  1732         
       
  1733         maskImageContext->drawBidiText(font, textRun, location);
       
  1734         
       
  1735         c->save();
       
  1736         c->clipToImageBuffer(maskRect, maskImage.get());
       
  1737         drawStyle->applyFillColor(c);
       
  1738         c->fillRect(maskRect);
       
  1739         c->restore();
       
  1740 
       
  1741         return;
       
  1742     }
       
  1743 #endif
       
  1744 
       
  1745     c->setTextDrawingMode(fill ? cTextFill : cTextStroke);
       
  1746     c->drawBidiText(font, textRun, location);
       
  1747 }
       
  1748 
       
  1749 const Font& CanvasRenderingContext2D::accessFont()
       
  1750 {
       
  1751     if (!state().m_realizedFont)
       
  1752         setFont(state().m_unparsedFont);
       
  1753     return state().m_font;
       
  1754 }
       
  1755 
       
  1756 } // namespace WebCore