Changeset 117106 in webkit


Ignore:
Timestamp:
May 15, 2012 11:43:21 AM (12 years ago)
Author:
Darin Adler
Message:

Optimize save/restore with no drawing operations between them (shows up on some canvas benchmarks)
https://bugs.webkit.org/show_bug.cgi?id=86448

Reviewed by Simon Fraser.

Since canvas programmers sometimes end up doing extra save/restore pairs with no actual drawing
in between, optimize that case by not realizing saves until we have to. This is doubly important
because saves are costly.

  • html/canvas/CanvasRenderingContext2D.cpp:

(WebCore::CanvasRenderingContext2D::CanvasRenderingContext2D): Initialize m_unrealizedSaveCount.
(WebCore::CanvasRenderingContext2D::isAccelerated): Improve performance by calling the
drawingContext function only once.
(WebCore::CanvasRenderingContext2D::reset): Set m_unrealizedSaveCount to 0.
(WebCore::CanvasRenderingContext2D::realizeSavesLoop): Added. Replaces the save function as the
function that actually pushes context onto the state stack.
(WebCore::CanvasRenderingContext2D::restore): Added code to do an early return if we can do the
restore just by decrementing the unrealized save count.
(WebCore::CanvasRenderingContext2D::setStrokeStyle): Added calls to realizeSaves and replaced
calls to state with calls to modifiableState.
(WebCore::CanvasRenderingContext2D::setFillStyle): Ditto.
(WebCore::CanvasRenderingContext2D::setLineWidth): Ditto. Also added an early out for cases where
the line width is not changing.
(WebCore::CanvasRenderingContext2D::setLineCap): Ditto.
(WebCore::CanvasRenderingContext2D::setLineJoin): Ditto.
(WebCore::CanvasRenderingContext2D::setMiterLimit): Ditto.
(WebCore::CanvasRenderingContext2D::setShadowOffsetX): Ditto.
(WebCore::CanvasRenderingContext2D::setShadowOffsetY): Ditto.
(WebCore::CanvasRenderingContext2D::setShadowBlur): Ditto.
(WebCore::CanvasRenderingContext2D::setShadowColor): Ditto.
(WebCore::CanvasRenderingContext2D::setWebkitLineDash): Ditto.
(WebCore::CanvasRenderingContext2D::setWebkitLineDashOffset): Ditto.
(WebCore::CanvasRenderingContext2D::setGlobalAlpha): Ditto.
(WebCore::CanvasRenderingContext2D::setGlobalCompositeOperation): Ditto.
(WebCore::CanvasRenderingContext2D::scale): Ditto.
(WebCore::CanvasRenderingContext2D::rotate): Ditto.
(WebCore::CanvasRenderingContext2D::translate): Ditto.
(WebCore::CanvasRenderingContext2D::transform): Ditto.
(WebCore::CanvasRenderingContext2D::setTransform): Ditto.
(WebCore::CanvasRenderingContext2D::setStrokeColor): Ditto.
(WebCore::CanvasRenderingContext2D::setFillColor): Ditto.
(WebCore::CanvasRenderingContext2D::clip): Ditto.
(WebCore::CanvasRenderingContext2D::clearRect): Changed implementation so it does not save
the graphics context in the common case where shadows, global alpha, and global compositing
operators do not interfer with the function's operation. This allowed us to get rid of the
setAllAttributesToDefault function, which was used nowhere else.
(WebCore::CanvasRenderingContext2D::setShadow): Added a new common bottleneck and made all
the setShadow functions call it.
(WebCore::CanvasRenderingContext2D::clearShadow): Changed to call the new setShadow.
(WebCore::CanvasRenderingContext2D::setFont): Renamed tempDecl to the more friendly
parsedStyle. Changed code structure so the CSS parser is deleted right after parsing is
done. Used string concatenation instead of more expensive string append. Added calls to
realizeSaves and modifiableState.
(WebCore::CanvasRenderingContext2D::setTextAlign): Added calls to realizeSaves and replaced
calls to state with calls to modifiableState. Also added an early out for cases where the
alignment is not changing.
(WebCore::CanvasRenderingContext2D::setTextBaseline): Ditto.

  • html/canvas/CanvasRenderingContext2D.h: Made save an inline function that bumps

m_unrealizedSaveCount. Removed setAllAttributesToDefault. Added OVERRIDE for all the
virtual function overrides, and made them all private. Moved m_path down with the other data
members. Renamed the non-const state function to modifiableState. Added a realizeSaves
function and the realizeSavesLoop for the unusual case where there is work to do.
Added m_unrealizedSaveCount.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r117102 r117106  
     12012-05-15  Darin Adler  <darin@apple.com>
     2
     3        Optimize save/restore with no drawing operations between them (shows up on some canvas benchmarks)
     4        https://bugs.webkit.org/show_bug.cgi?id=86448
     5
     6        Reviewed by Simon Fraser.
     7
     8        Since canvas programmers sometimes end up doing extra save/restore pairs with no actual drawing
     9        in between, optimize that case by not realizing saves until we have to. This is doubly important
     10        because saves are costly.
     11
     12        * html/canvas/CanvasRenderingContext2D.cpp:
     13        (WebCore::CanvasRenderingContext2D::CanvasRenderingContext2D): Initialize m_unrealizedSaveCount.
     14        (WebCore::CanvasRenderingContext2D::isAccelerated): Improve performance by calling the
     15        drawingContext function only once.
     16        (WebCore::CanvasRenderingContext2D::reset): Set m_unrealizedSaveCount to 0.
     17        (WebCore::CanvasRenderingContext2D::realizeSavesLoop): Added. Replaces the save function as the
     18        function that actually pushes context onto the state stack.
     19        (WebCore::CanvasRenderingContext2D::restore): Added code to do an early return if we can do the
     20        restore just by decrementing the unrealized save count.
     21        (WebCore::CanvasRenderingContext2D::setStrokeStyle): Added calls to realizeSaves and replaced
     22        calls to state with calls to modifiableState.
     23        (WebCore::CanvasRenderingContext2D::setFillStyle): Ditto.
     24        (WebCore::CanvasRenderingContext2D::setLineWidth): Ditto. Also added an early out for cases where
     25        the line width is not changing.
     26        (WebCore::CanvasRenderingContext2D::setLineCap): Ditto.
     27        (WebCore::CanvasRenderingContext2D::setLineJoin): Ditto.
     28        (WebCore::CanvasRenderingContext2D::setMiterLimit): Ditto.
     29        (WebCore::CanvasRenderingContext2D::setShadowOffsetX): Ditto.
     30        (WebCore::CanvasRenderingContext2D::setShadowOffsetY): Ditto.
     31        (WebCore::CanvasRenderingContext2D::setShadowBlur): Ditto.
     32        (WebCore::CanvasRenderingContext2D::setShadowColor): Ditto.
     33        (WebCore::CanvasRenderingContext2D::setWebkitLineDash): Ditto.
     34        (WebCore::CanvasRenderingContext2D::setWebkitLineDashOffset): Ditto.
     35        (WebCore::CanvasRenderingContext2D::setGlobalAlpha): Ditto.
     36        (WebCore::CanvasRenderingContext2D::setGlobalCompositeOperation): Ditto.
     37        (WebCore::CanvasRenderingContext2D::scale): Ditto.
     38        (WebCore::CanvasRenderingContext2D::rotate): Ditto.
     39        (WebCore::CanvasRenderingContext2D::translate): Ditto.
     40        (WebCore::CanvasRenderingContext2D::transform): Ditto.
     41        (WebCore::CanvasRenderingContext2D::setTransform): Ditto.
     42        (WebCore::CanvasRenderingContext2D::setStrokeColor): Ditto.
     43        (WebCore::CanvasRenderingContext2D::setFillColor): Ditto.
     44        (WebCore::CanvasRenderingContext2D::clip): Ditto.
     45        (WebCore::CanvasRenderingContext2D::clearRect): Changed implementation so it does not save
     46        the graphics context in the common case where shadows, global alpha, and global compositing
     47        operators do not interfer with the function's operation. This allowed us to get rid of the
     48        setAllAttributesToDefault function, which was used nowhere else.
     49        (WebCore::CanvasRenderingContext2D::setShadow): Added a new common bottleneck and made all
     50        the setShadow functions call it.
     51        (WebCore::CanvasRenderingContext2D::clearShadow): Changed to call the new setShadow.
     52        (WebCore::CanvasRenderingContext2D::setFont): Renamed tempDecl to the more friendly
     53        parsedStyle. Changed code structure so the CSS parser is deleted right after parsing is
     54        done. Used string concatenation instead of more expensive string append. Added calls to
     55        realizeSaves and modifiableState.
     56        (WebCore::CanvasRenderingContext2D::setTextAlign): Added calls to realizeSaves and replaced
     57        calls to state with calls to modifiableState. Also added an early out for cases where the
     58        alignment is not changing.
     59        (WebCore::CanvasRenderingContext2D::setTextBaseline): Ditto.
     60
     61        * html/canvas/CanvasRenderingContext2D.h: Made save an inline function that bumps
     62        m_unrealizedSaveCount. Removed setAllAttributesToDefault. Added OVERRIDE for all the
     63        virtual function overrides, and made them all private. Moved m_path down with the other data
     64        members. Renamed the non-const state function to modifiableState. Added a realizeSaves
     65        function and the realizeSavesLoop for the unusual case where there is work to do.
     66        Added m_unrealizedSaveCount.
     67
    1682012-05-15  Tommy Widenflycht  <tommyw@google.com>
    269
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp

    r116723 r117106  
    11/*
    2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
    33 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
    44 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
     
    116116    : CanvasRenderingContext(canvas)
    117117    , m_stateStack(1)
     118    , m_unrealizedSaveCount(0)
    118119    , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
    119120#if ENABLE(DASHBOARD_SUPPORT)
     
    149150{
    150151#if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
    151     return canvas()->hasCreatedImageBuffer() && drawingContext() && drawingContext()->isAcceleratedContext();
     152    if (!canvas()->hasCreatedImageBuffer())
     153        return false;
     154    GraphicsContext* context = drawingContext();
     155    return context && context->isAcceleratedContext();
    152156#else
    153157    return false;
     
    161165    m_stateStack.first() = State();
    162166    m_path.clear();
     167    m_unrealizedSaveCount = 0;
    163168}
    164169
     
    260265}
    261266
    262 void CanvasRenderingContext2D::save()
    263 {
     267void CanvasRenderingContext2D::realizeSavesLoop()
     268{
     269    ASSERT(m_unrealizedSaveCount);
    264270    ASSERT(m_stateStack.size() >= 1);
    265     m_stateStack.append(state());
    266     GraphicsContext* c = drawingContext();
    267     if (!c)
    268         return;
    269     c->save();
     271    GraphicsContext* context = drawingContext();
     272    do {
     273        m_stateStack.append(state());
     274        if (context)
     275            context->save();
     276    } while (--m_unrealizedSaveCount);
    270277}
    271278
    272279void CanvasRenderingContext2D::restore()
    273280{
     281    if (m_unrealizedSaveCount) {
     282        --m_unrealizedSaveCount;
     283        return;
     284    }
    274285    ASSERT(m_stateStack.size() >= 1);
    275286    if (m_stateStack.size() <= 1)
     
    282293        return;
    283294    c->restore();
    284 }
    285 
    286 void CanvasRenderingContext2D::setAllAttributesToDefault()
    287 {
    288     state().m_globalAlpha = 1;
    289     state().m_shadowOffset = FloatSize();
    290     state().m_shadowBlur = 0;
    291     state().m_shadowColor = Color::transparent;
    292     state().m_globalComposite = CompositeSourceOver;
    293 
    294     GraphicsContext* context = drawingContext();
    295     if (!context)
    296         return;
    297 
    298     applyShadow();
    299     context->setAlpha(1);
    300     context->setCompositeOperation(CompositeSourceOver);
    301295}
    302296
     
    324318        checkOrigin(style->canvasPattern());
    325319
    326     state().m_strokeStyle = style.release();
     320    realizeSaves();
     321    modifiableState().m_strokeStyle = style.release();
    327322    GraphicsContext* c = drawingContext();
    328323    if (!c)
    329324        return;
    330325    state().m_strokeStyle->applyStrokeColor(c);
    331     state().m_unparsedStrokeColor = String();
     326    modifiableState().m_unparsedStrokeColor = String();
    332327}
    333328
     
    355350        checkOrigin(style->canvasPattern());
    356351
    357     state().m_fillStyle = style.release();
     352    realizeSaves();
     353    modifiableState().m_fillStyle = style.release();
    358354    GraphicsContext* c = drawingContext();
    359355    if (!c)
    360356        return;
    361357    state().m_fillStyle->applyFillColor(c);
    362     state().m_unparsedFillColor = String();
     358    modifiableState().m_unparsedFillColor = String();
    363359}
    364360
     
    372368    if (!(isfinite(width) && width > 0))
    373369        return;
    374     state().m_lineWidth = width;
     370    if (state().m_lineWidth == width)
     371        return;
     372    realizeSaves();
     373    modifiableState().m_lineWidth = width;
    375374    GraphicsContext* c = drawingContext();
    376375    if (!c)
     
    389388    if (!parseLineCap(s, cap))
    390389        return;
    391     state().m_lineCap = cap;
     390    if (state().m_lineCap == cap)
     391        return;
     392    realizeSaves();
     393    modifiableState().m_lineCap = cap;
    392394    GraphicsContext* c = drawingContext();
    393395    if (!c)
     
    406408    if (!parseLineJoin(s, join))
    407409        return;
    408     state().m_lineJoin = join;
     410    if (state().m_lineJoin == join)
     411        return;
     412    realizeSaves();
     413    modifiableState().m_lineJoin = join;
    409414    GraphicsContext* c = drawingContext();
    410415    if (!c)
     
    422427    if (!(isfinite(limit) && limit > 0))
    423428        return;
    424     state().m_miterLimit = limit;
     429    if (state().m_miterLimit == limit)
     430        return;
     431    realizeSaves();
     432    modifiableState().m_miterLimit = limit;
    425433    GraphicsContext* c = drawingContext();
    426434    if (!c)
     
    438446    if (!isfinite(x))
    439447        return;
    440     state().m_shadowOffset.setWidth(x);
     448    if (state().m_shadowOffset.width() == x)
     449        return;
     450    realizeSaves();
     451    modifiableState().m_shadowOffset.setWidth(x);
    441452    applyShadow();
    442453}
     
    451462    if (!isfinite(y))
    452463        return;
    453     state().m_shadowOffset.setHeight(y);
     464    if (state().m_shadowOffset.height() == y)
     465        return;
     466    realizeSaves();
     467    modifiableState().m_shadowOffset.setHeight(y);
    454468    applyShadow();
    455469}
     
    464478    if (!(isfinite(blur) && blur >= 0))
    465479        return;
    466     state().m_shadowBlur = blur;
     480    if (state().m_shadowBlur == blur)
     481        return;
     482    realizeSaves();
     483    modifiableState().m_shadowBlur = blur;
    467484    applyShadow();
    468485}
     
    475492void CanvasRenderingContext2D::setShadowColor(const String& color)
    476493{
    477     if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas()))
    478         return;
     494    RGBA32 rgba;
     495    if (!parseColorOrCurrentColor(rgba, color, canvas()))
     496        return;
     497    if (state().m_shadowColor == rgba)
     498        return;
     499    realizeSaves();
     500    modifiableState().m_shadowColor = rgba;
    479501    applyShadow();
    480502}
     
    487509void CanvasRenderingContext2D::setWebkitLineDash(const DashArray& dash)
    488510{
    489     state().m_lineDash = dash;
    490 
     511    if (state().m_lineDash == dash)
     512        return;
     513    realizeSaves();
     514    modifiableState().m_lineDash = dash;
    491515    GraphicsContext* c = drawingContext();
    492516    if (!c)
     
    504528    if (!isfinite(offset))
    505529        return;
    506 
    507     state().m_lineDashOffset = offset;
    508 
     530    if (state().m_lineDashOffset == offset)
     531        return;
     532    realizeSaves();
     533    modifiableState().m_lineDashOffset = offset;
    509534    GraphicsContext* c = drawingContext();
    510535    if (!c)
     
    522547    if (!(alpha >= 0 && alpha <= 1))
    523548        return;
    524     state().m_globalAlpha = alpha;
     549    if (state().m_globalAlpha == alpha)
     550        return;
     551    realizeSaves();
     552    modifiableState().m_globalAlpha = alpha;
    525553    GraphicsContext* c = drawingContext();
    526554    if (!c)
     
    539567    if (!parseCompositeOperator(operation, op))
    540568        return;
    541     state().m_globalComposite = op;
     569    if (state().m_globalComposite == op)
     570        return;
     571    realizeSaves();
     572    modifiableState().m_globalComposite = op;
    542573    GraphicsContext* c = drawingContext();
    543574    if (!c)
     
    559590    AffineTransform newTransform = state().m_transform;
    560591    newTransform.scaleNonUniform(sx, sy);
     592    if (state().m_transform == newTransform)
     593        return;
     594
     595    realizeSaves();
     596
    561597    if (!newTransform.isInvertible()) {
    562         state().m_invertibleCTM = false;
    563         return;
    564     }
    565 
    566     state().m_transform = newTransform;
     598        modifiableState().m_invertibleCTM = false;
     599        return;
     600    }
     601
     602    modifiableState().m_transform = newTransform;
    567603    c->scale(FloatSize(sx, sy));
    568604    m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
     
    582618    AffineTransform newTransform = state().m_transform;
    583619    newTransform.rotate(angleInRadians / piDouble * 180.0);
     620    if (state().m_transform == newTransform)
     621        return;
     622
     623    realizeSaves();
     624
    584625    if (!newTransform.isInvertible()) {
    585         state().m_invertibleCTM = false;
    586         return;
    587     }
    588 
    589     state().m_transform = newTransform;
     626        modifiableState().m_invertibleCTM = false;
     627        return;
     628    }
     629
     630    modifiableState().m_transform = newTransform;
    590631    c->rotate(angleInRadians);
    591632    m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
     
    605646    AffineTransform newTransform = state().m_transform;
    606647    newTransform.translate(tx, ty);
     648    if (state().m_transform == newTransform)
     649        return;
     650
     651    realizeSaves();
     652
    607653    if (!newTransform.isInvertible()) {
    608         state().m_invertibleCTM = false;
    609         return;
    610     }
    611 
    612     state().m_transform = newTransform;
     654        modifiableState().m_invertibleCTM = false;
     655        return;
     656    }
     657
     658    modifiableState().m_transform = newTransform;
    613659    c->translate(tx, ty);
    614660    m_path.transform(AffineTransform().translate(-tx, -ty));
     
    628674    AffineTransform transform(m11, m12, m21, m22, dx, dy);
    629675    AffineTransform newTransform = state().m_transform * transform;
     676    if (state().m_transform == newTransform)
     677        return;
     678
     679    realizeSaves();
     680
    630681    if (!newTransform.isInvertible()) {
    631         state().m_invertibleCTM = false;
    632         return;
    633     }
    634 
    635     state().m_transform = newTransform;
     682        modifiableState().m_invertibleCTM = false;
     683        return;
     684    }
     685
     686    modifiableState().m_transform = newTransform;
    636687    c->concatCTM(transform);
    637688    m_path.transform(transform.inverse());
     
    650701    if (!ctm.isInvertible())
    651702        return;
     703
     704    realizeSaves();
     705   
    652706    c->setCTM(canvas()->baseTransform());
    653     state().m_transform = AffineTransform();
     707    modifiableState().m_transform = AffineTransform();
    654708    m_path.transform(ctm);
    655709
    656     state().m_invertibleCTM = true;
     710    modifiableState().m_invertibleCTM = true;
    657711    transform(m11, m12, m21, m22, dx, dy);
    658712}
     
    662716    if (color == state().m_unparsedStrokeColor)
    663717        return;
     718    realizeSaves();
    664719    setStrokeStyle(CanvasStyle::createFromString(color, canvas()->document()));
    665     state().m_unparsedStrokeColor = color;
     720    modifiableState().m_unparsedStrokeColor = color;
    666721}
    667722
     
    703758    if (color == state().m_unparsedFillColor)
    704759        return;
     760    realizeSaves();
    705761    setFillStyle(CanvasStyle::createFromString(color, canvas()->document()));
    706     state().m_unparsedFillColor = color;
     762    modifiableState().m_unparsedFillColor = color;
    707763}
    708764
     
    9721028    if (!state().m_invertibleCTM)
    9731029        return;
     1030    realizeSaves();
    9741031    c->canvasClip(m_path);
    9751032#if ENABLE(DASHBOARD_SUPPORT)
     
    10051062    FloatRect rect(x, y, width, height);
    10061063
    1007     save();
    1008     setAllAttributesToDefault();
     1064    bool saved = false;
     1065    if (shouldDrawShadows()) {
     1066        context->save();
     1067        saved = true;
     1068        context->setLegacyShadow(FloatSize(), 0, Color::transparent, ColorSpaceDeviceRGB);
     1069    }
     1070    if (state().m_globalAlpha != 1) {
     1071        if (!saved) {
     1072            context->save();
     1073            saved = true;
     1074        }
     1075        context->setAlpha(1);
     1076    }
     1077    if (state().m_globalComposite != CompositeSourceOver) {
     1078        if (!saved) {
     1079            context->save();
     1080            saved = true;
     1081        }
     1082        context->setCompositeOperation(CompositeSourceOver);
     1083    }
    10091084    context->clearRect(rect);
     1085    if (saved)
     1086        context->restore();
    10101087    didDraw(rect);
    1011     restore();
    10121088}
    10131089
     
    10801156void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
    10811157{
    1082     state().m_shadowOffset = FloatSize(width, height);
    1083     state().m_shadowBlur = blur;
    1084     state().m_shadowColor = Color::transparent;
    1085     applyShadow();
     1158    setShadow(FloatSize(width, height), blur, Color::transparent);
    10861159}
    10871160
    10881161void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
    10891162{
    1090     if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas()))
    1091         return;
    1092 
    1093     state().m_shadowOffset = FloatSize(width, height);
    1094     state().m_shadowBlur = blur;
    1095     applyShadow();
     1163    RGBA32 rgba;
     1164    if (!parseColorOrCurrentColor(rgba, color, canvas()))
     1165        return;
     1166    setShadow(FloatSize(width, height), blur, rgba);
    10961167}
    10971168
    10981169void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
    10991170{
    1100     state().m_shadowOffset = FloatSize(width, height);
    1101     state().m_shadowBlur = blur;
    1102     state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f);
    1103     applyShadow();
     1171    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1));
    11041172}
    11051173
     
    11071175{
    11081176    RGBA32 rgba;
    1109 
    11101177    if (!parseColorOrCurrentColor(rgba, color, canvas()))
    11111178        return;
    1112 
    1113     state().m_shadowColor = colorWithOverrideAlpha(rgba, alpha);
    1114     state().m_shadowOffset = FloatSize(width, height);
    1115     state().m_shadowBlur = blur;
    1116     applyShadow();
     1179    setShadow(FloatSize(width, height), blur, colorWithOverrideAlpha(rgba, alpha));
    11171180}
    11181181
    11191182void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
    11201183{
    1121     state().m_shadowOffset = FloatSize(width, height);
    1122     state().m_shadowBlur = blur;
    1123     state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha);
    1124     applyShadow();
     1184    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha));
    11251185}
    11261186
    11271187void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
    11281188{
    1129     state().m_shadowOffset = FloatSize(width, height);
    1130     state().m_shadowBlur = blur;
    1131     state().m_shadowColor = makeRGBA32FromFloats(r, g, b, a);
    1132     applyShadow();
     1189    setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(r, g, b, a));
    11331190}
    11341191
    11351192void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
    11361193{
    1137     state().m_shadowOffset = FloatSize(width, height);
    1138     state().m_shadowBlur = blur;
    1139     state().m_shadowColor = makeRGBAFromCMYKA(c, m, y, k, a);
    1140     applyShadow();
     1194    setShadow(FloatSize(width, height), blur, makeRGBAFromCMYKA(c, m, y, k, a));
    11411195}
    11421196
    11431197void CanvasRenderingContext2D::clearShadow()
    11441198{
    1145     state().m_shadowOffset = FloatSize();
    1146     state().m_shadowBlur = 0;
    1147     state().m_shadowColor = Color::transparent;
     1199    setShadow(FloatSize(), 0, Color::transparent);
     1200}
     1201
     1202void CanvasRenderingContext2D::setShadow(const FloatSize& offset, float blur, RGBA32 color)
     1203{
     1204    if (state().m_shadowOffset == offset && state().m_shadowBlur == blur && state().m_shadowColor == color)
     1205        return;
     1206    bool wasDrawingShadows = shouldDrawShadows();
     1207    realizeSaves();
     1208    modifiableState().m_shadowOffset = offset;
     1209    modifiableState().m_shadowBlur = blur;
     1210    modifiableState().m_shadowColor = color;
     1211    if (!wasDrawingShadows && !shouldDrawShadows())
     1212        return;
    11481213    applyShadow();
    11491214}
     
    19241989void CanvasRenderingContext2D::setFont(const String& newFont)
    19251990{
    1926     RefPtr<StylePropertySet> tempDecl = StylePropertySet::create();
    1927     CSSParser parser(strictToCSSParserMode(!m_usesCSSCompatibilityParseMode));
    1928 
    1929     String declarationText("font: ");
    1930     declarationText += newFont;
    1931     parser.parseDeclaration(tempDecl.get(), declarationText, 0, 0);
    1932     if (tempDecl->isEmpty())
     1991    RefPtr<StylePropertySet> parsedStyle = StylePropertySet::create();
     1992    CSSParser(strictToCSSParserMode(!m_usesCSSCompatibilityParseMode)).parseDeclaration(parsedStyle.get(), "font:" + newFont, 0, 0);
     1993    if (parsedStyle->isEmpty())
    19331994        return;
    19341995
    19351996    // The parse succeeded.
    1936     state().m_unparsedFont = newFont;
     1997    realizeSaves();
     1998    modifiableState().m_unparsedFont = newFont;
    19371999
    19382000    // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
     
    19452007    // Now map the font property longhands into the style.
    19462008    StyleResolver* styleResolver = canvas()->styleResolver();
    1947     styleResolver->applyPropertyToStyle(CSSPropertyFontFamily, tempDecl->getPropertyCSSValue(CSSPropertyFontFamily).get(), newStyle.get());
    1948     styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontStyle, tempDecl->getPropertyCSSValue(CSSPropertyFontStyle).get());
    1949     styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontVariant, tempDecl->getPropertyCSSValue(CSSPropertyFontVariant).get());
    1950     styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontWeight, tempDecl->getPropertyCSSValue(CSSPropertyFontWeight).get());
     2009    styleResolver->applyPropertyToStyle(CSSPropertyFontFamily, parsedStyle->getPropertyCSSValue(CSSPropertyFontFamily).get(), newStyle.get());
     2010    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontStyle, parsedStyle->getPropertyCSSValue(CSSPropertyFontStyle).get());
     2011    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontVariant, parsedStyle->getPropertyCSSValue(CSSPropertyFontVariant).get());
     2012    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontWeight, parsedStyle->getPropertyCSSValue(CSSPropertyFontWeight).get());
    19512013
    19522014    // As described in BUG66291, setting font-size on a font may entail a CSSPrimitiveValue::computeLengthDouble call,
     
    19542016    // The updateFont() call below updates the fontMetrics and ensures the proper setting of font-size.
    19552017    styleResolver->updateFont();
    1956     styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontSize, tempDecl->getPropertyCSSValue(CSSPropertyFontSize).get());
    1957     styleResolver->applyPropertyToCurrentStyle(CSSPropertyLineHeight, tempDecl->getPropertyCSSValue(CSSPropertyLineHeight).get());
    1958 
    1959     state().m_font = newStyle->font();
    1960     state().m_font.update(styleResolver->fontSelector());
    1961     state().m_realizedFont = true;
    1962     styleResolver->fontSelector()->registerForInvalidationCallbacks(&state());
     2018    styleResolver->applyPropertyToCurrentStyle(CSSPropertyFontSize, parsedStyle->getPropertyCSSValue(CSSPropertyFontSize).get());
     2019    styleResolver->applyPropertyToCurrentStyle(CSSPropertyLineHeight, parsedStyle->getPropertyCSSValue(CSSPropertyLineHeight).get());
     2020
     2021    modifiableState().m_font = newStyle->font();
     2022    modifiableState().m_font.update(styleResolver->fontSelector());
     2023    modifiableState().m_realizedFont = true;
     2024    styleResolver->fontSelector()->registerForInvalidationCallbacks(&modifiableState());
    19632025}
    19642026
     
    19732035    if (!parseTextAlign(s, align))
    19742036        return;
    1975     state().m_textAlign = align;
     2037    if (state().m_textAlign == align)
     2038        return;
     2039    realizeSaves();
     2040    modifiableState().m_textAlign = align;
    19762041}
    19772042
     
    19862051    if (!parseTextBaseline(s, baseline))
    19872052        return;
    1988     state().m_textBaseline = baseline;
     2053    if (state().m_textBaseline == baseline)
     2054        return;
     2055    realizeSaves();
     2056    modifiableState().m_textBaseline = baseline;
    19892057}
    19902058
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h

    r114679 r117106  
    11/*
    2  * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    6767    virtual ~CanvasRenderingContext2D();
    6868
    69     virtual bool is2d() const { return true; }
    70     virtual bool isAccelerated() const;
    71 
    7269    CanvasStyle* strokeStyle() const;
    7370    void setStrokeStyle(PassRefPtr<CanvasStyle>);
     
    112109    void setGlobalCompositeOperation(const String&);
    113110
    114     void save();
     111    void save() { ++m_unrealizedSaveCount; }
    115112    void restore();
    116     void setAllAttributesToDefault();
    117113
    118114    void scale(float sx, float sy);
     
    227223    LineJoin getLineJoin() const { return state().m_lineJoin; }
    228224
    229 #if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
    230     virtual PlatformLayer* platformLayer() const;
    231 #endif
    232 
    233225private:
    234226    struct State : FontSelectorClient {
     
    239231        State& operator=(const State&);
    240232
    241         virtual void fontsNeedUpdate(FontSelector*);
     233        virtual void fontsNeedUpdate(FontSelector*) OVERRIDE;
    242234
    243235        String m_unparsedStrokeColor;
     
    278270    CanvasRenderingContext2D(HTMLCanvasElement*, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode);
    279271
    280     Path m_path;
    281 
    282     State& state() { return m_stateStack.last(); }
     272    State& modifiableState() { ASSERT(!m_unrealizedSaveCount); return m_stateStack.last(); }
    283273    const State& state() const { return m_stateStack.last(); }
    284274
     275    void setShadow(const FloatSize& offset, float blur, RGBA32 color);
    285276    void applyShadow();
    286277    bool shouldDrawShadows() const;
     
    292283
    293284    void unwindStateStack();
     285    void realizeSaves()
     286    {
     287        if (m_unrealizedSaveCount)
     288            realizeSavesLoop();
     289    }
     290    void realizeSavesLoop();
    294291
    295292    void applyStrokePattern();
     
    323320    void putImageData(ImageData*, ImageBuffer::CoordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode&);
    324321
     322    virtual bool is2d() const OVERRIDE { return true; }
     323    virtual bool isAccelerated() const OVERRIDE;
     324
     325#if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
     326    virtual PlatformLayer* platformLayer() const OVERRIDE;
     327#endif
     328
     329    Path m_path;   
    325330    Vector<State, 1> m_stateStack;
     331    unsigned m_unrealizedSaveCount;
    326332    bool m_usesCSSCompatibilityParseMode;
    327333#if ENABLE(DASHBOARD_SUPPORT)
Note: See TracChangeset for help on using the changeset viewer.