Changeset 53949 in webkit


Ignore:
Timestamp:
Jan 27, 2010 1:14:03 PM (14 years ago)
Author:
oliver@apple.com
Message:

2010-01-27 Oliver Hunt <oliver@apple.com>

Reviewed by Simon Fraser.

Animated scaling of background-image is too slow
https://bugs.webkit.org/show_bug.cgi?id=33808

Implement a version of the RenderImage animated scaling optimisation
for background images. Due to the possibility of arbitrary transforms
being applied to containing elements we explicitly check the current
CTM of the context for scaling or rotation.

  • platform/graphics/GraphicsContext.cpp: (WebCore::GraphicsContext::drawTiledImage):
  • platform/graphics/GraphicsContext.h:
  • platform/graphics/transforms/TransformationMatrix.h: (WebCore::TransformationMatrix::isIdentityOrTranslation):
  • rendering/RenderBoxModelObject.cpp: (WebCore::RenderBoxModelScaleData::RenderBoxModelScaleData): (WebCore::RenderBoxModelScaleData::~RenderBoxModelScaleData): (WebCore::RenderBoxModelScaleData::size): (WebCore::RenderBoxModelScaleData::time): (WebCore::RenderBoxModelScaleData::useLowQualityScale): (WebCore::RenderBoxModelScaleData::hiqhQualityRepaintTimer): (WebCore::RenderBoxModelScaleData::setSize): (WebCore::RenderBoxModelScaleData::setTime): (WebCore::RenderBoxModelScaleData::setUseLowQualityScale): (WebCore::RenderBoxModelScaleObserver::boxModelObjectDestroyed): (WebCore::RenderBoxModelScaleObserver::highQualityRepaintTimerFired): (WebCore::RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality): (WebCore::RenderBoxModelObject::highQualityRepaintTimerFired): (WebCore::RenderBoxModelObject::~RenderBoxModelObject): (WebCore::RenderBoxModelObject::paintFillLayerExtended):
  • rendering/RenderBoxModelObject.h:
Location:
trunk/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r53947 r53949  
     12010-01-27  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Simon Fraser.
     4
     5        Animated scaling of background-image is too slow
     6        https://bugs.webkit.org/show_bug.cgi?id=33808
     7
     8        Implement a version of the RenderImage animated scaling optimisation
     9        for background images.  Due to the possibility of arbitrary transforms
     10        being applied to containing elements we explicitly check the current
     11        CTM of the context for scaling or rotation.
     12
     13        * platform/graphics/GraphicsContext.cpp:
     14        (WebCore::GraphicsContext::drawTiledImage):
     15        * platform/graphics/GraphicsContext.h:
     16        * platform/graphics/transforms/TransformationMatrix.h:
     17        (WebCore::TransformationMatrix::isIdentityOrTranslation):
     18        * rendering/RenderBoxModelObject.cpp:
     19        (WebCore::RenderBoxModelScaleData::RenderBoxModelScaleData):
     20        (WebCore::RenderBoxModelScaleData::~RenderBoxModelScaleData):
     21        (WebCore::RenderBoxModelScaleData::size):
     22        (WebCore::RenderBoxModelScaleData::time):
     23        (WebCore::RenderBoxModelScaleData::useLowQualityScale):
     24        (WebCore::RenderBoxModelScaleData::hiqhQualityRepaintTimer):
     25        (WebCore::RenderBoxModelScaleData::setSize):
     26        (WebCore::RenderBoxModelScaleData::setTime):
     27        (WebCore::RenderBoxModelScaleData::setUseLowQualityScale):
     28        (WebCore::RenderBoxModelScaleObserver::boxModelObjectDestroyed):
     29        (WebCore::RenderBoxModelScaleObserver::highQualityRepaintTimerFired):
     30        (WebCore::RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality):
     31        (WebCore::RenderBoxModelObject::highQualityRepaintTimerFired):
     32        (WebCore::RenderBoxModelObject::~RenderBoxModelObject):
     33        (WebCore::RenderBoxModelObject::paintFillLayerExtended):
     34        * rendering/RenderBoxModelObject.h:
     35
    1362010-01-27  Yael Aharon  <yael.aharon@nokia.com>
    237
  • trunk/WebCore/platform/graphics/GraphicsContext.cpp

    r52791 r53949  
    412412}
    413413
    414 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op)
     414void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
    415415{
    416416    if (paintingDisabled() || !image)
    417417        return;
    418 
     418    if (useLowQualityScale) {
     419        save();
     420        setImageInterpolationQuality(InterpolationLow);
     421    }
    419422    image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
    420 }
    421 
    422 void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op)
     423    if (useLowQualityScale)
     424        restore();
     425}
     426
     427void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
    423428{
    424429    if (paintingDisabled() || !image)
    425430        return;
    426431
     432    if (useLowQualityScale) {
     433        save();
     434        setImageInterpolationQuality(InterpolationLow);
     435    }
    427436    if (hRule == Image::StretchTile && vRule == Image::StretchTile)
    428437        // Just do a scale.
    429         return drawImage(image, styleColorSpace, dest, srcRect, op);
    430 
    431     image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
     438        drawImage(image, styleColorSpace, dest, srcRect, op);
     439    else
     440        image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
     441    if (useLowQualityScale)
     442        restore();
    432443}
    433444
  • trunk/WebCore/platform/graphics/GraphicsContext.h

    r53857 r53949  
    221221                       CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
    222222        void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize,
    223                        CompositeOperator = CompositeSourceOver);
     223                       CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
    224224        void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect,
    225225                            Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
    226                             CompositeOperator = CompositeSourceOver);
     226                            CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
    227227
    228228        void setImageInterpolationQuality(InterpolationQuality);
  • trunk/WebCore/platform/graphics/transforms/TransformationMatrix.h

    r53485 r53949  
    320320#endif
    321321
     322    bool isIdentityOrTranslation() const
     323    {
     324        return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0
     325            && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0
     326            && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0
     327            && m_matrix[3][3] == 1;
     328    }
     329
    322330private:
    323331    // multiply passed 2D point by matrix (assume z=0)
    324332    void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
    325    
     333
    326334    // multiply passed 3D point by matrix
    327335    void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
    328    
     336
    329337    void setMatrix(const Matrix4 m)
    330338    {
     
    332340            memcpy(m_matrix, m, sizeof(Matrix4));
    333341    }
    334    
    335     bool isIdentityOrTranslation() const
    336     {
    337         return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
    338                m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
    339                m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
    340                m_matrix[3][3] == 1;
    341     }
    342    
     342
    343343    Matrix4 m_matrix;
    344344};
  • trunk/WebCore/rendering/RenderBoxModelObject.cpp

    r53476 r53949  
    4545bool RenderBoxModelObject::s_layerWasSelfPainting = false;
    4646
     47static const double cInterpolationCutoff = 800. * 800.;
     48static const double cLowQualityTimeThreshold = 0.500; // 500 ms
     49
     50class RenderBoxModelScaleData : public Noncopyable {
     51public:
     52    RenderBoxModelScaleData(RenderBoxModelObject* object, const IntSize& size, double time, bool lowQualityScale)
     53        : m_size(size)
     54        , m_lastPaintTime(time)
     55        , m_lowQualityScale(lowQualityScale)
     56        , m_highQualityRepaintTimer(object, &RenderBoxModelObject::highQualityRepaintTimerFired)
     57    {
     58    }
     59
     60    ~RenderBoxModelScaleData()
     61    {
     62        m_highQualityRepaintTimer.stop();
     63    }
     64
     65    Timer<RenderBoxModelObject>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; }
     66
     67    const IntSize& size() const { return m_size; }
     68    void setSize(const IntSize& s) { m_size = s; }
     69    double lastPaintTime() const { return m_lastPaintTime; }
     70    void setLastPaintTime(double t) { m_lastPaintTime = t; }
     71    bool useLowQualityScale() const { return m_lowQualityScale; }
     72    void setUseLowQualityScale(bool b)
     73    {
     74        m_highQualityRepaintTimer.stop();
     75        m_lowQualityScale = b;
     76        if (b)
     77            m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold);
     78    }
     79
     80private:
     81    IntSize m_size;
     82    double m_lastPaintTime;
     83    bool m_lowQualityScale;
     84    Timer<RenderBoxModelObject> m_highQualityRepaintTimer;
     85};
     86
     87class RenderBoxModelScaleObserver {
     88public:
     89    static bool shouldPaintBackgroundAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const IntSize&);
     90
     91    static void boxModelObjectDestroyed(RenderBoxModelObject* object)
     92    {
     93        if (gBoxModelObjects) {
     94            RenderBoxModelScaleData* data = gBoxModelObjects->take(object);
     95            delete data;
     96            if (!gBoxModelObjects->size()) {
     97                delete gBoxModelObjects;
     98                gBoxModelObjects = 0;
     99            }
     100        }
     101    }
     102
     103    static void highQualityRepaintTimerFired(RenderBoxModelObject* object)
     104    {
     105        RenderBoxModelScaleObserver::boxModelObjectDestroyed(object);
     106        object->repaint();
     107    }
     108
     109    static HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* gBoxModelObjects;
     110};
     111
     112bool RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const IntSize& size)
     113{
     114    // If the image is not a bitmap image, then none of this is relevant and we just paint at high
     115    // quality.
     116    if (!image->isBitmapImage())
     117        return false;
     118
     119    // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
     120    // is actually being scaled.
     121    IntSize imageSize(image->width(), image->height());
     122
     123    // Look ourselves up in the hashtable.
     124    RenderBoxModelScaleData* data = 0;
     125    if (gBoxModelObjects)
     126        data = gBoxModelObjects->get(object);
     127
     128    bool contextIsScaled = !context->getCTM().isIdentityOrTranslation();
     129    if (!contextIsScaled && imageSize == size) {
     130        // There is no scale in effect.  If we had a scale in effect before, we can just delete this data.
     131        if (data) {
     132            gBoxModelObjects->remove(object);
     133            delete data;
     134        }
     135        return false;
     136    }
     137
     138    // There is no need to hash scaled images that always use low quality mode when the page demands it.  This is the iChat case.
     139    if (object->document()->page()->inLowQualityImageInterpolationMode()) {
     140        double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
     141        if (totalPixels > cInterpolationCutoff)
     142            return true;
     143    }
     144
     145    // If there is no data yet, we will paint the first scale at high quality and record the paint time in case a second scale happens
     146    // very soon.
     147    if (!data) {
     148        data = new RenderBoxModelScaleData(object, size, currentTime(), false);
     149        if (!gBoxModelObjects)
     150            gBoxModelObjects = new HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>;
     151        gBoxModelObjects->set(object, data);
     152        return false;
     153    }
     154
     155    // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with.
     156    if (!contextIsScaled && data->size() == size)
     157        return data->useLowQualityScale();
     158
     159    // We have data and our size just changed.  If this change happened quickly, go into low quality mode and then set a repaint
     160    // timer to paint in high quality mode.  Otherwise it is ok to just paint in high quality mode.
     161    double newTime = currentTime();
     162    data->setUseLowQualityScale(newTime - data->lastPaintTime() < cLowQualityTimeThreshold);
     163    data->setLastPaintTime(newTime);
     164    data->setSize(size);
     165    return data->useLowQualityScale();
     166}
     167
     168HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* RenderBoxModelScaleObserver::gBoxModelObjects = 0;
     169
     170void RenderBoxModelObject::highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*)
     171{
     172    RenderBoxModelScaleObserver::highQualityRepaintTimerFired(this);
     173}
     174
    47175RenderBoxModelObject::RenderBoxModelObject(Node* node)
    48176    : RenderObject(node)
     
    56184    ASSERT(!hasLayer());
    57185    ASSERT(!m_layer);
     186    RenderBoxModelScaleObserver::boxModelObjectDestroyed(this);
    58187}
    59188
     
    308437{
    309438    GraphicsContext* context = paintInfo.context;
     439    if (context->paintingDisabled())
     440        return;
     441
    310442    bool includeLeftEdge = box ? box->includeLeftEdge() : true;
    311443    bool includeRightEdge = box ? box->includeRightEdge() : true;
     
    465597            CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
    466598            RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
    467             context->drawTiledImage(bg->image(clientForBackgroundImage, tileSize), style()->colorSpace(), destRect, phase, tileSize, compositeOp);
     599            Image* image = bg->image(clientForBackgroundImage, tileSize);
     600            bool useLowQualityScaling = RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(context, this, image, destRect.size());
     601            context->drawTiledImage(image, style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling);
    468602        }
    469603    }
  • trunk/WebCore/rendering/RenderBoxModelObject.h

    r53291 r53949  
    9999    void destroyLayer();
    100100
     101    void highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*);
     102
    101103protected:
    102104    void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize);
Note: See TracChangeset for help on using the changeset viewer.