Changeset 109273 in webkit


Ignore:
Timestamp:
Feb 29, 2012 3:10:06 PM (12 years ago)
Author:
Beth Dakin
Message:

https://bugs.webkit.org/show_bug.cgi?id=79705
didNewFirstVisuallyNonEmptyLayout should be enhanced to look at size instead
of a raw tally
-and corresponding-
<rdar://problem/10821314>

Reviewed by Dave Hyatt.

Instead of firing didNewFirstVisuallyNonEmptyLayout() when a raw tally of
relevant painted objects has reached a port-defined threshold, this patch
looks at the size of those objects with respect to the view area. The patch
also looks at relevant objects that cannot yet be fully painted, such as
incrementally loading images.

We no longer need a HashSet for the relevant painted objects since Region can
do all of the heavy lifting. We now have a Region for the painted and
unpainted regions. We do need a HashSet for the unpainted objects though,
because we need to know if a painted object needs to be subtracted from the
unpainted region before being added to the painted region.

  • page/Page.cpp:

(WebCore):
(WebCore::Page::isCountingRelevantRepaintedObjects):
(WebCore::Page::startCountingRelevantRepaintedObjects):
(WebCore::Page::resetRelevantPaintedObjectCounter):
(WebCore::Page::addRelevantRepaintedObject):
(WebCore::Page::addRelevantUnpaintedObject):

  • page/Page.h:

(Page):

New function on Region iterates through the rects and calculates the total
area.

  • platform/graphics/Region.cpp:

(WebCore::Region::totalArea):
(WebCore):

  • platform/graphics/Region.h:

(Region):

Remove code from these classes since they are not actually relevant objects.

  • rendering/InlineBox.cpp:

(WebCore::InlineBox::paint):

  • rendering/RenderRegion.cpp:

(WebCore::RenderRegion::paintReplaced):

  • rendering/RenderReplaced.cpp:

(WebCore::RenderReplaced::paint):

All of these other callers send a rect that actually represents their size
(usually the visualOverflowRect) instead of the paintInfo's paintRect, and
they call addRelevantUnpaintedObject when appropriate.

  • rendering/InlineTextBox.cpp:

(WebCore::InlineTextBox::paint):

  • rendering/RenderEmbeddedObject.cpp:

(WebCore::RenderEmbeddedObject::paint):
(WebCore::RenderEmbeddedObject::paintReplaced):

  • rendering/RenderHTMLCanvas.cpp:

(WebCore::RenderHTMLCanvas::paintReplaced):

  • rendering/RenderImage.cpp:

(WebCore::RenderImage::paintReplaced):

  • rendering/RenderVideo.cpp:

(WebCore::RenderVideo::paintReplaced):

  • rendering/svg/RenderSVGRoot.cpp:

(WebCore::RenderSVGRoot::paintReplaced):

Location:
trunk/Source/WebCore
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r109271 r109273  
     12012-02-29  Beth Dakin  <bdakin@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=79705
     4        didNewFirstVisuallyNonEmptyLayout should be enhanced to look at size instead
     5        of a raw tally
     6        -and corresponding-
     7        <rdar://problem/10821314>
     8
     9        Reviewed by Dave Hyatt.
     10
     11        Instead of firing didNewFirstVisuallyNonEmptyLayout() when a raw tally of
     12        relevant painted objects has reached a port-defined threshold, this patch
     13        looks at the size of those objects with respect to the view area. The patch
     14        also looks at relevant objects that cannot yet be fully painted, such as
     15        incrementally loading images.
     16
     17        We no longer need a HashSet for the relevant painted objects since Region can
     18        do all of the heavy lifting. We now have a Region for the painted and
     19        unpainted regions. We do need a HashSet for the unpainted objects though,
     20        because we need to know if a painted object needs to be subtracted from the
     21        unpainted region before being added to the painted region.
     22        * page/Page.cpp:
     23        (WebCore):
     24        (WebCore::Page::isCountingRelevantRepaintedObjects):
     25        (WebCore::Page::startCountingRelevantRepaintedObjects):
     26        (WebCore::Page::resetRelevantPaintedObjectCounter):
     27        (WebCore::Page::addRelevantRepaintedObject):
     28        (WebCore::Page::addRelevantUnpaintedObject):
     29        * page/Page.h:
     30        (Page):
     31
     32        New function on Region iterates through the rects and calculates the total
     33        area.
     34        * platform/graphics/Region.cpp:
     35        (WebCore::Region::totalArea):
     36        (WebCore):
     37        * platform/graphics/Region.h:
     38        (Region):
     39
     40        Remove code from these classes since they are not actually relevant objects.
     41        * rendering/InlineBox.cpp:
     42        (WebCore::InlineBox::paint):
     43        * rendering/RenderRegion.cpp:
     44        (WebCore::RenderRegion::paintReplaced):
     45        * rendering/RenderReplaced.cpp:
     46        (WebCore::RenderReplaced::paint):
     47
     48        All of these other callers send a rect that actually represents their size
     49        (usually the visualOverflowRect) instead of the paintInfo's paintRect, and
     50        they call addRelevantUnpaintedObject when appropriate.
     51        * rendering/InlineTextBox.cpp:
     52        (WebCore::InlineTextBox::paint):
     53        * rendering/RenderEmbeddedObject.cpp:
     54        (WebCore::RenderEmbeddedObject::paint):
     55        (WebCore::RenderEmbeddedObject::paintReplaced):
     56        * rendering/RenderHTMLCanvas.cpp:
     57        (WebCore::RenderHTMLCanvas::paintReplaced):
     58        * rendering/RenderImage.cpp:
     59        (WebCore::RenderImage::paintReplaced):
     60        * rendering/RenderVideo.cpp:
     61        (WebCore::RenderVideo::paintReplaced):
     62        * rendering/svg/RenderSVGRoot.cpp:
     63        (WebCore::RenderSVGRoot::paintReplaced):
     64
    1652012-02-29  Joshua Bell  <jsbell@chromium.org>
    266
  • trunk/Source/WebCore/page/Page.cpp

    r108958 r109273  
    10101010#endif
    10111011
     1012// FIXME: gPaintedObjectCounterThreshold is no longer used for calculating relevant repainted areas,
     1013// and it should be removed. For the time being, it is useful because it allows us to avoid doing
     1014// any of this work for ports that don't make sure of didNewFirstVisuallyNonEmptyLayout. We should
     1015// remove this when we resolve <rdar://problem/10791680> Need to merge didFirstVisuallyNonEmptyLayout
     1016// and didNewFirstVisuallyNonEmptyLayout
    10121017static uint64_t gPaintedObjectCounterThreshold = 0;
    10131018
     1019// These are magical constants that might be tweaked over time.
     1020static double gMinimumPaintedAreaRatio = 0.1;
     1021static double gMaximumUnpaintedAreaRatio = 0.1;
     1022
    10141023void Page::setRelevantRepaintedObjectsCounterThreshold(uint64_t threshold)
    10151024{
     
    10171026}
    10181027
     1028bool Page::isCountingRelevantRepaintedObjects() const
     1029{
     1030    return m_isCountingRelevantRepaintedObjects && gPaintedObjectCounterThreshold > 0;
     1031}
     1032
    10191033void Page::startCountingRelevantRepaintedObjects()
    10201034{
    10211035    m_isCountingRelevantRepaintedObjects = true;
    10221036
    1023     // Clear the HashSet in case we didn't hit the threshold last time.
    1024     m_relevantPaintedRenderObjects.clear();
     1037    // Reset everything in case we didn't hit the threshold last time.
     1038    resetRelevantPaintedObjectCounter();
     1039}
     1040
     1041void Page::resetRelevantPaintedObjectCounter()
     1042{
     1043    m_relevantUnpaintedRenderObjects.clear();
     1044    m_relevantPaintedRegion = Region();
     1045    m_relevantUnpaintedRegion = Region();
    10251046}
    10261047
    10271048void Page::addRelevantRepaintedObject(RenderObject* object, const IntRect& objectPaintRect)
    10281049{
    1029     if (!m_isCountingRelevantRepaintedObjects)
    1030         return;
    1031 
    1032     // We don't need to do anything if there is no counter threshold.
    1033     if (!gPaintedObjectCounterThreshold)
     1050    if (!isCountingRelevantRepaintedObjects())
    10341051        return;
    10351052
     
    10401057    }
    10411058
    1042     m_relevantPaintedRenderObjects.add(object);
    1043 
    1044     if (m_relevantPaintedRenderObjects.size() == static_cast<int>(gPaintedObjectCounterThreshold)) {
     1059    // If this object was previously counted as an unpainted object, remove it from that HashSet
     1060    // and corresponding Region. FIXME: This doesn't do the right thing if the objects overlap.
     1061    if (m_relevantUnpaintedRenderObjects.contains(object)) {
     1062        m_relevantUnpaintedRenderObjects.remove(object);
     1063        m_relevantUnpaintedRegion.subtract(objectPaintRect);
     1064    }
     1065
     1066    m_relevantPaintedRegion.unite(objectPaintRect);
     1067
     1068    RenderView* view = object->view();
     1069    if (!view)
     1070        return;
     1071   
     1072    float viewArea = view->viewRect().width() * view->viewRect().height();
     1073    float ratioOfViewThatIsPainted = m_relevantPaintedRegion.totalArea() / viewArea;
     1074    float ratioOfViewThatIsUnpainted = m_relevantUnpaintedRegion.totalArea() / viewArea;
     1075
     1076    if (ratioOfViewThatIsPainted > gMinimumPaintedAreaRatio && ratioOfViewThatIsUnpainted < gMaximumUnpaintedAreaRatio) {
    10451077        m_isCountingRelevantRepaintedObjects = false;
    1046         m_relevantPaintedRenderObjects.clear();
     1078        resetRelevantPaintedObjectCounter();
    10471079        if (Frame* frame = mainFrame())
    10481080            frame->loader()->didNewFirstVisuallyNonEmptyLayout();
    10491081    }
     1082}
     1083
     1084void Page::addRelevantUnpaintedObject(RenderObject* object, const IntRect& objectPaintRect)
     1085{
     1086    if (!isCountingRelevantRepaintedObjects())
     1087        return;
     1088
     1089    // The objects are only relevant if they are being painted within the viewRect().
     1090    if (RenderView* view = object->view()) {
     1091        if (!objectPaintRect.intersects(pixelSnappedIntRect(view->viewRect())))
     1092            return;
     1093    }
     1094
     1095    m_relevantUnpaintedRenderObjects.add(object);
     1096    m_relevantUnpaintedRegion.unite(objectPaintRect);
    10501097}
    10511098
  • trunk/Source/WebCore/page/Page.h

    r108958 r109273  
    2828#include "PlatformScreen.h"
    2929#include "PlatformString.h"
     30#include "Region.h"
    3031#include "Supplementable.h"
    3132#include "ViewportArguments.h"
     
    321322        PlatformDisplayID displayID() const { return m_displayID; }
    322323
     324        bool isCountingRelevantRepaintedObjects() const;
    323325        void setRelevantRepaintedObjectsCounterThreshold(uint64_t);
    324326        void startCountingRelevantRepaintedObjects();
     327        void resetRelevantPaintedObjectCounter();
    325328        void addRelevantRepaintedObject(RenderObject*, const IntRect& objectPaintRect);
     329        void addRelevantUnpaintedObject(RenderObject*, const IntRect& objectPaintRect);
    326330
    327331    private:
     
    419423        PlatformDisplayID m_displayID;
    420424
    421         HashSet<RenderObject*> m_relevantPaintedRenderObjects;
     425        HashSet<RenderObject*> m_relevantUnpaintedRenderObjects;
     426        Region m_relevantPaintedRegion;
     427        Region m_relevantUnpaintedRegion;
    422428        bool m_isCountingRelevantRepaintedObjects;
    423429    };
  • trunk/Source/WebCore/platform/graphics/Region.cpp

    r108433 r109273  
    7878}
    7979
     80unsigned Region::totalArea() const
     81{
     82    Vector<IntRect> rects = this->rects();
     83    size_t size = rects.size();
     84    unsigned totalArea = 0;
     85
     86    for (size_t i = 0; i < size; ++i) {
     87        IntRect rect = rects[i];
     88        totalArea += (rect.width() * rect.height());
     89    }
     90
     91    return totalArea;
     92}
     93
    8094Region::Shape::Shape()
    8195{
  • trunk/Source/WebCore/platform/graphics/Region.h

    r107013 r109273  
    5252
    5353    bool contains(const IntPoint&) const;
     54
     55    unsigned totalArea() const;
    5456
    5557#ifndef NDEBUG
  • trunk/Source/WebCore/rendering/InlineBox.cpp

    r106492 r109273  
    214214        return;
    215215
    216     if (Frame* frame = renderer()->frame()) {
    217         if (Page* page = frame->page())
    218             page->addRelevantRepaintedObject(renderer(), paintInfo.rect);
    219     }
    220 
    221216    LayoutPoint childPoint = paintOffset;
    222217    if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
  • trunk/Source/WebCore/rendering/InlineTextBox.cpp

    r106492 r109273  
    498498
    499499    if (Frame* frame = renderer()->frame()) {
    500         if (Page* page = frame->page())
    501             page->addRelevantRepaintedObject(renderer(), paintInfo.rect);
     500        if (Page* page = frame->page()) {
     501            // FIXME: Right now, InlineTextBoxes never call addRelevantUnpaintedObject() even though they might
     502            // legitimately be unpainted if they are waiting on a slow-loading web font. We should fix that, and
     503            // when we do, we will have to account for the fact the InlineTextBoxes do not always have unique
     504            // renderers and Page currently relies on each unpainted object having a unique renderer.
     505            if (paintInfo.phase == PaintPhaseForeground)
     506                page->addRelevantRepaintedObject(renderer(), IntRect(adjustedPaintOffset.x(), adjustedPaintOffset.y(), logicalWidth(), logicalHeight()));
     507        }
    502508    }
    503509
  • trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp

    r107296 r109273  
    140140void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    141141{
     142    Page* page = 0;
     143    if (Frame* frame = this->frame())
     144        page = frame->page();
     145
    142146    if (pluginCrashedOrWasMissing()) {
     147        if (page && paintInfo.phase == PaintPhaseForeground)
     148            page->addRelevantUnpaintedObject(this, visualOverflowRect());
    143149        RenderReplaced::paint(paintInfo, paintOffset);
    144150        return;
    145151    }
    146    
     152
     153    if (page && paintInfo.phase == PaintPhaseForeground)
     154        page->addRelevantRepaintedObject(this, visualOverflowRect());
     155
    147156    RenderPart::paint(paintInfo, paintOffset);
    148157}
     
    168177    if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, font, run, textWidth))
    169178        return;
    170 
    171     if (Frame* frame = this->frame()) {
    172         if (Page* page = frame->page())
    173             page->addRelevantRepaintedObject(this, paintInfo.rect);
    174     }
    175179   
    176180    GraphicsContextStateSaver stateSaver(*context);
  • trunk/Source/WebCore/rendering/RenderHTMLCanvas.cpp

    r106492 r109273  
    5959void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    6060{
     61    LayoutRect rect = contentBoxRect();
     62    rect.moveBy(paintOffset);
     63
    6164    if (Frame* frame = this->frame()) {
    62         if (Page* page = frame->page())
    63             page->addRelevantRepaintedObject(this, paintInfo.rect);
     65        if (Page* page = frame->page()) {
     66            if (paintInfo.phase == PaintPhaseForeground)
     67                page->addRelevantRepaintedObject(this, rect);
     68        }
    6469    }
    6570
    66     LayoutRect rect = contentBoxRect();
    67     rect.moveBy(paintOffset);
    6871    bool useLowQualityScale = style()->imageRendering() == ImageRenderingOptimizeContrast;
    6972    static_cast<HTMLCanvasElement*>(node())->paint(paintInfo.context, rect, useLowQualityScale);
  • trunk/Source/WebCore/rendering/RenderImage.cpp

    r107461 r109273  
    265265    GraphicsContext* context = paintInfo.context;
    266266
     267    Page* page = 0;
     268    if (Frame* frame = this->frame())
     269        page = frame->page();
     270
    267271    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) {
    268272        if (paintInfo.phase == PaintPhaseSelection)
    269273            return;
     274
     275        if (page && paintInfo.phase == PaintPhaseForeground)
     276            page->addRelevantUnpaintedObject(this, visualOverflowRect());
    270277
    271278        if (cWidth > 2 && cHeight > 2) {
     
    326333    } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) {
    327334        RefPtr<Image> img = m_imageResource->image(cWidth, cHeight);
    328         if (!img || img->isNull())
     335        if (!img || img->isNull()) {
     336            if (page && paintInfo.phase == PaintPhaseForeground)
     337                page->addRelevantUnpaintedObject(this, visualOverflowRect());
    329338            return;
    330 
    331     if (Frame* frame = this->frame()) {
    332         if (Page* page = frame->page())
    333             page->addRelevantRepaintedObject(this, paintInfo.rect);
     339        }
     340
     341    if (page && paintInfo.phase == PaintPhaseForeground) {
     342        // For now, count images as unpainted if they are still progressively loading. We may want
     343        // to refine this in the future to account for the portion of the image that has painted.
     344        if (cachedImage()->isLoading())
     345            page->addRelevantUnpaintedObject(this, visualOverflowRect());
     346        else
     347            page->addRelevantRepaintedObject(this, visualOverflowRect());
    334348    }
    335349
  • trunk/Source/WebCore/rendering/RenderRegion.cpp

    r108952 r109273  
    140140        return;
    141141
    142     if (Frame* frame = this->frame()) {
    143         if (Page* page = frame->page())
    144             page->addRelevantRepaintedObject(this, paintInfo.rect);
    145     }
    146 
    147142    setRegionBoxesRegionStyle();
    148143    m_flowThread->paintIntoRegion(paintInfo, this, LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop()));
  • trunk/Source/WebCore/rendering/RenderReplaced.cpp

    r109246 r109273  
    138138    }
    139139
    140     if (Frame* frame = this->frame()) {
    141         if (Page* page = frame->page())
    142             page->addRelevantRepaintedObject(this, paintInfo.rect);
    143     }
    144 
    145140    bool completelyClippedOut = false;
    146141    if (style()->hasBorderRadius()) {
  • trunk/Source/WebCore/rendering/RenderVideo.cpp

    r106492 r109273  
    199199    bool displayingPoster = videoElement()->shouldDisplayPosterImage();
    200200
     201    Page* page = 0;
     202    if (Frame* frame = this->frame())
     203        page = frame->page();
     204
    201205    if (!displayingPoster) {
    202         if (!mediaPlayer)
     206        if (!mediaPlayer) {
     207            if (page && paintInfo.phase == PaintPhaseForeground)
     208                page->addRelevantUnpaintedObject(this, visualOverflowRect());
    203209            return;
     210        }
    204211        updatePlayer();
    205212    }
    206213
    207214    LayoutRect rect = videoBox();
    208     if (rect.isEmpty())
    209         return;
     215    if (rect.isEmpty()) {
     216        if (page && paintInfo.phase == PaintPhaseForeground)
     217            page->addRelevantUnpaintedObject(this, visualOverflowRect());
     218        return;
     219    }
    210220    rect.moveBy(paintOffset);
    211221
    212     if (Frame* frame = this->frame()) {
    213         if (Page* page = frame->page())
    214             page->addRelevantRepaintedObject(this, paintInfo.rect);
    215     }
     222    if (page && paintInfo.phase == PaintPhaseForeground)
     223        page->addRelevantRepaintedObject(this, visualOverflowRect());
    216224
    217225    if (displayingPoster)
  • trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp

    r109104 r109273  
    250250        return;
    251251
     252    Page* page = 0;
     253    if (Frame* frame = this->frame())
     254        page = frame->page();
     255
    252256    // Don't paint if we don't have kids, except if we have filters we should paint those.
    253257    if (!firstChild()) {
    254258        SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this);
    255         if (!resources || !resources->filter())
     259        if (!resources || !resources->filter()) {
     260            if (page && paintInfo.phase == PaintPhaseForeground)
     261                page->addRelevantUnpaintedObject(this, visualOverflowRect());
    256262            return;
    257     }
    258 
    259     if (Frame* frame = this->frame()) {
    260         if (Page* page = frame->page())
    261             page->addRelevantRepaintedObject(this, paintInfo.rect);
    262     }
     263        }
     264    }
     265
     266    if (page && paintInfo.phase == PaintPhaseForeground)
     267        page->addRelevantRepaintedObject(this, visualOverflowRect());
    263268
    264269    // Make a copy of the PaintInfo because applyTransform will modify the damage rect.
Note: See TracChangeset for help on using the changeset viewer.