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