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