Changeset 167930 in webkit


Ignore:
Timestamp:
Apr 29, 2014 7:54:47 AM (10 years ago)
Author:
abucur@adobe.com
Message:

[CSS Regions] Fix getClientRects() for content nodes
https://bugs.webkit.org/show_bug.cgi?id=117407

Reviewed by David Hyatt.

Source/WebCore:
This patch modifies getClientRects() to return a list of fragments
for a fragmented box instead of a single rectangle positioned inside
the region where the box center would appear.

The approach is to split the border box of the element in regions using
the layout positioning. Then each fragment is mapped to the view coordinates
and the result added to the list of rectangles. To preserve the originating
region when mapping the fragment through the ancestor tree I've introduced
the concept of a current region. The current region is stored inside a
CurrentRenderRegionMaintainer object, created whenever an algorithm needing
it needs to run. When the maintainer is destroyed, the cleanup is made
automatically. The RenderFlowThread holds a pointer to this structure for
easy access.

Tests: fast/regions/cssom/client-rects-fixed-content.html

fast/regions/cssom/client-rects-forced-breaks.html
fast/regions/cssom/client-rects-inline-complex.html
fast/regions/cssom/client-rects-inline.html
fast/regions/cssom/client-rects-nested-regions.html
fast/regions/cssom/client-rects-positioned.html
fast/regions/cssom/client-rects-relative-position.html
fast/regions/cssom/client-rects-simple-block.html
fast/regions/cssom/client-rects-transforms.html
fast/regions/cssom/client-rects-unsplittable-float.html

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::absoluteQuads): Split the box in fragments.

  • rendering/RenderBox.cpp:

(WebCore::RenderBox::absoluteQuads): Split the box in fragments.

  • rendering/RenderFlowThread.cpp:

(WebCore::RenderFlowThread::RenderFlowThread):
(WebCore::RenderFlowThread::mapFromFlowToRegion):
(WebCore::RenderFlowThread::mapLocalToContainer):
(WebCore::RenderFlowThread::currentRegion):

  • rendering/RenderFlowThread.h:
  • rendering/RenderNamedFlowFragment.cpp:

(WebCore::RenderNamedFlowFragment::absoluteQuadsForBoxInRegion): Get
the fragments for this box in the region.

  • rendering/RenderNamedFlowFragment.h:
  • rendering/RenderNamedFlowThread.cpp:

(WebCore::RenderNamedFlowThread::absoluteQuadsForBox): Virtual function
that can be used to implement fragments to client rects mapping.

  • rendering/RenderNamedFlowThread.h:
  • rendering/RenderRegion.cpp:

(WebCore::RenderRegion::rectFlowPortionForBox): Small change to correctly
map empty rectangles to containers.
(WebCore::CurrentRenderRegionMaintainer::CurrentRenderRegionMaintainer):
(WebCore::CurrentRenderRegionMaintainer::~CurrentRenderRegionMaintainer):

  • rendering/RenderRegion.h:

(WebCore::RenderRegion::absoluteQuadsForBoxInRegion):
(WebCore::CurrentRenderRegionMaintainer::region):

LayoutTests:
Tests verifying getClientRects works correctly in different situations.

  • fast/regions/cssom/client-rects-fixed-content-expected.txt: Added.
  • fast/regions/cssom/client-rects-fixed-content.html: Added.
  • fast/regions/cssom/client-rects-forced-breaks-expected.txt: Added.
  • fast/regions/cssom/client-rects-forced-breaks.html: Added.
  • fast/regions/cssom/client-rects-inline-complex-expected.txt: Added.
  • fast/regions/cssom/client-rects-inline-complex.html: Added.
  • fast/regions/cssom/client-rects-inline-expected.txt: Added.
  • fast/regions/cssom/client-rects-inline.html: Added.
  • fast/regions/cssom/client-rects-nested-regions-expected.txt: Added.
  • fast/regions/cssom/client-rects-nested-regions.html: Added.
  • fast/regions/cssom/client-rects-positioned-expected.txt: Added.
  • fast/regions/cssom/client-rects-positioned.html: Added.
  • fast/regions/cssom/client-rects-relative-position-expected.txt: Added.
  • fast/regions/cssom/client-rects-relative-position.html: Added.
  • fast/regions/cssom/client-rects-simple-block-expected.txt: Added.
  • fast/regions/cssom/client-rects-simple-block.html: Added.
  • fast/regions/cssom/client-rects-transforms-expected.txt: Added.
  • fast/regions/cssom/client-rects-transforms.html: Added.
  • fast/regions/cssom/client-rects-unsplittable-float-expected.txt: Added.
  • fast/regions/cssom/client-rects-unsplittable-float.html: Added.
  • fast/regions/resources/helper.js:

(testClientRects): Function that compares the actual client rects for an
element to a list of expected client rects.

Location:
trunk
Files:
20 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r167928 r167930  
     12014-04-29  Andrei Bucur  <abucur@adobe.com>
     2
     3        [CSS Regions] Fix getClientRects() for content nodes
     4        https://bugs.webkit.org/show_bug.cgi?id=117407
     5
     6        Reviewed by David Hyatt.
     7
     8        Tests verifying getClientRects works correctly in different situations.
     9
     10        * fast/regions/cssom/client-rects-fixed-content-expected.txt: Added.
     11        * fast/regions/cssom/client-rects-fixed-content.html: Added.
     12        * fast/regions/cssom/client-rects-forced-breaks-expected.txt: Added.
     13        * fast/regions/cssom/client-rects-forced-breaks.html: Added.
     14        * fast/regions/cssom/client-rects-inline-complex-expected.txt: Added.
     15        * fast/regions/cssom/client-rects-inline-complex.html: Added.
     16        * fast/regions/cssom/client-rects-inline-expected.txt: Added.
     17        * fast/regions/cssom/client-rects-inline.html: Added.
     18        * fast/regions/cssom/client-rects-nested-regions-expected.txt: Added.
     19        * fast/regions/cssom/client-rects-nested-regions.html: Added.
     20        * fast/regions/cssom/client-rects-positioned-expected.txt: Added.
     21        * fast/regions/cssom/client-rects-positioned.html: Added.
     22        * fast/regions/cssom/client-rects-relative-position-expected.txt: Added.
     23        * fast/regions/cssom/client-rects-relative-position.html: Added.
     24        * fast/regions/cssom/client-rects-simple-block-expected.txt: Added.
     25        * fast/regions/cssom/client-rects-simple-block.html: Added.
     26        * fast/regions/cssom/client-rects-transforms-expected.txt: Added.
     27        * fast/regions/cssom/client-rects-transforms.html: Added.
     28        * fast/regions/cssom/client-rects-unsplittable-float-expected.txt: Added.
     29        * fast/regions/cssom/client-rects-unsplittable-float.html: Added.
     30        * fast/regions/resources/helper.js:
     31        (testClientRects): Function that compares the actual client rects for an
     32        element to a list of expected client rects.
     33
    1342014-04-29  Andrei Bucur  <abucur@adobe.com>
    235
  • trunk/LayoutTests/fast/regions/resources/helper.js

    r160978 r167930  
    7070        var rect = document.getElementById(name).getBoundingClientRect();
    7171        assertEqualRects(results, name, rectToArray(rect), expectedBoundingRects[name], tolerance);
     72    }
     73
     74    document.write("<p>" + (results.length ? results.join("<br />") : "PASS") + "</p>");
     75   
     76    return !results.length;
     77}
     78
     79function testClientRects(id, expectedClientRects, tolerance)
     80{
     81    if (tolerance === undefined)
     82        tolerance = 0;
     83
     84    var results = [];
     85    var actualRects = document.getElementById(id).getClientRects();
     86    if (actualRects.length != expectedClientRects.length)
     87        results.push("FAIL: The element #" + id + " has a wrong count of client rects: " + actualRects.length + "(actual) vs. " + expectedClientRects.length + "(expected)");
     88    else {
     89        for (var i = 0; i < expectedClientRects.length; ++i) {
     90            var expectedRect = expectedClientRects[i];
     91            var actualRect = actualRects[i];
     92            assertEqualRects(results, id, rectToArray(actualRect), expectedRect, tolerance);
     93        }
    7294    }
    7395
  • trunk/Source/WebCore/ChangeLog

    r167928 r167930  
     12014-04-29  Andrei Bucur  <abucur@adobe.com>
     2
     3        [CSS Regions] Fix getClientRects() for content nodes
     4        https://bugs.webkit.org/show_bug.cgi?id=117407
     5
     6        Reviewed by David Hyatt.
     7
     8        This patch modifies getClientRects() to return a list of fragments
     9        for a fragmented box instead of a single rectangle positioned inside
     10        the region where the box center would appear.
     11
     12        The approach is to split the border box of the element in regions using
     13        the layout positioning. Then each fragment is mapped to the view coordinates
     14        and the result added to the list of rectangles. To preserve the originating
     15        region when mapping the fragment through the ancestor tree I've introduced
     16        the concept of a current region. The current region is stored inside a
     17        CurrentRenderRegionMaintainer object, created whenever an algorithm needing
     18        it needs to run. When the maintainer is destroyed, the cleanup is made
     19        automatically. The RenderFlowThread holds a pointer to this structure for
     20        easy access.
     21
     22        Tests: fast/regions/cssom/client-rects-fixed-content.html
     23               fast/regions/cssom/client-rects-forced-breaks.html
     24               fast/regions/cssom/client-rects-inline-complex.html
     25               fast/regions/cssom/client-rects-inline.html
     26               fast/regions/cssom/client-rects-nested-regions.html
     27               fast/regions/cssom/client-rects-positioned.html
     28               fast/regions/cssom/client-rects-relative-position.html
     29               fast/regions/cssom/client-rects-simple-block.html
     30               fast/regions/cssom/client-rects-transforms.html
     31               fast/regions/cssom/client-rects-unsplittable-float.html
     32
     33        * rendering/RenderBlock.cpp:
     34        (WebCore::RenderBlock::absoluteQuads): Split the box in fragments.
     35        * rendering/RenderBox.cpp:
     36        (WebCore::RenderBox::absoluteQuads): Split the box in fragments.
     37        * rendering/RenderFlowThread.cpp:
     38        (WebCore::RenderFlowThread::RenderFlowThread):
     39        (WebCore::RenderFlowThread::mapFromFlowToRegion):
     40        (WebCore::RenderFlowThread::mapLocalToContainer):
     41        (WebCore::RenderFlowThread::currentRegion):
     42        * rendering/RenderFlowThread.h:
     43        * rendering/RenderNamedFlowFragment.cpp:
     44        (WebCore::RenderNamedFlowFragment::absoluteQuadsForBoxInRegion): Get
     45        the fragments for this box in the region.
     46        * rendering/RenderNamedFlowFragment.h:
     47        * rendering/RenderNamedFlowThread.cpp:
     48        (WebCore::RenderNamedFlowThread::absoluteQuadsForBox): Virtual function
     49        that can be used to implement fragments to client rects mapping.
     50        * rendering/RenderNamedFlowThread.h:
     51        * rendering/RenderRegion.cpp:
     52        (WebCore::RenderRegion::rectFlowPortionForBox): Small change to correctly
     53        map empty rectangles to containers.
     54        (WebCore::CurrentRenderRegionMaintainer::CurrentRenderRegionMaintainer):
     55        (WebCore::CurrentRenderRegionMaintainer::~CurrentRenderRegionMaintainer):
     56        * rendering/RenderRegion.h:
     57        (WebCore::RenderRegion::absoluteQuadsForBoxInRegion):
     58        (WebCore::CurrentRenderRegionMaintainer::region):
     59
    1602014-04-29  Andrei Bucur  <abucur@adobe.com>
    261
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r167820 r167930  
    46994699    // inline boxes above and below us (thus getting merged with them to form a single irregular
    47004700    // shape).
    4701     if (isAnonymousBlockContinuation()) {
    4702         // FIXME: This is wrong for block-flows that are horizontal.
    4703         // https://bugs.webkit.org/show_bug.cgi?id=46781
    4704         FloatRect localRect(0, -collapsedMarginBefore(),
    4705                             width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
     4701    FloatRect localRect = isAnonymousBlockContinuation()
     4702        ? FloatRect(0, -collapsedMarginBefore(), width(), height() + collapsedMarginBefore() + collapsedMarginAfter())
     4703        : FloatRect(0, 0, width(), height());
     4704   
     4705    // FIXME: This is wrong for block-flows that are horizontal.
     4706    // https://bugs.webkit.org/show_bug.cgi?id=46781
     4707    RenderFlowThread* flowThread = flowThreadContainingBlock();
     4708    if (!flowThread || !flowThread->absoluteQuadsForBox(quads, wasFixed, this, localRect.y(), localRect.maxY()))
    47064709        quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed));
     4710
     4711    if (isAnonymousBlockContinuation())
    47074712        continuation()->absoluteQuads(quads, wasFixed);
    4708     } else
    4709         quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
    47104713}
    47114714
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r167810 r167930  
    556556void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
    557557{
    558     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
     558    FloatRect localRect(0, 0, width(), height());
     559
     560    RenderFlowThread* flowThread = flowThreadContainingBlock();
     561    if (flowThread && flowThread->absoluteQuadsForBox(quads, wasFixed, this, localRect.y(), localRect.maxY()))
     562        return;
     563
     564    quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed));
    559565}
    560566
  • trunk/Source/WebCore/rendering/RenderFlowThread.cpp

    r167928 r167930  
    5656    , m_previousRegionCount(0)
    5757    , m_autoLogicalHeightRegionsCount(0)
     58    , m_currentRegionMaintainer(nullptr)
    5859    , m_regionsInvalidated(false)
    5960    , m_regionsHaveUniformLogicalWidth(true)
     
    543544        return 0;
    544545
    545     LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox();
    546     flipForWritingMode(boxRect);
    547 
    548     // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions,
    549     // for now we just take the center of the mapped enclosing box and map it to a region.
    550     // Note: Using the center in order to avoid rounding errors.
    551 
    552     LayoutPoint center = boxRect.center();
    553     RenderRegion* renderRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(this, isHorizontalWritingMode() ? center.y() : center.x(), true, DisallowRegionAutoGeneration);
    554     if (!renderRegion)
    555         return 0;
     546    RenderRegion* renderRegion = currentRegion();
     547    if (!renderRegion) {
     548        LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox();
     549        flipForWritingMode(boxRect);
     550
     551        LayoutPoint center = boxRect.center();
     552        renderRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(this, isHorizontalWritingMode() ? center.y() : center.x(), true, DisallowRegionAutoGeneration);
     553        if (!renderRegion)
     554            return 0;
     555    }
    556556
    557557    LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect());
     
    12241224    if (RenderRegion* region = mapFromFlowToRegion(transformState)) {
    12251225        // FIXME: The cast below is probably not the best solution, we may need to find a better way.
    1226         static_cast<const RenderObject*>(region)->mapLocalToContainer(region->containerForRepaint(), transformState, mode, wasFixed);
     1226        const RenderObject* regionObject = static_cast<const RenderObject*>(region);
     1227
     1228        // If the repaint container is nullptr, we have to climb up to the RenderView, otherwise swap
     1229        // it with the region's repaint container.
     1230        repaintContainer = repaintContainer ? region->containerForRepaint() : nullptr;
     1231
     1232        if (RenderFlowThread* regionFlowThread = region->flowThreadContainingBlock()) {
     1233            RenderRegion* startRegion = nullptr;
     1234            RenderRegion* endRegion = nullptr;
     1235            if (regionFlowThread->getRegionRangeForBox(region, startRegion, endRegion)) {
     1236                CurrentRenderRegionMaintainer regionMaintainer(*startRegion);
     1237                regionObject->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
     1238                return;
     1239            }
     1240        }
     1241
     1242        regionObject->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
    12271243    }
    12281244}
     
    14441460}
    14451461
     1462RenderRegion* RenderFlowThread::currentRegion() const
     1463{
     1464    return m_currentRegionMaintainer ? &m_currentRegionMaintainer->region() : nullptr;
     1465}
     1466
    14461467ContainingRegionMap& RenderFlowThread::containingRegionMap()
    14471468{
  • trunk/Source/WebCore/rendering/RenderFlowThread.h

    r167928 r167930  
    3939namespace WebCore {
    4040
     41class CurrentRenderRegionMaintainer;
    4142struct LayerFragment;
    4243typedef Vector<LayerFragment, 1> LayerFragments;
     
    221222    // Used to estimate the maximum height of the flow thread.
    222223    static LayoutUnit maxLogicalHeight() { return LayoutUnit::max() / 2; }
    223    
     224
    224225    bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const;
    225226
     227    virtual bool absoluteQuadsForBox(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) const { return false; }
     228
    226229    virtual void layout() override;
     230
     231    void setCurrentRegionMaintainer(CurrentRenderRegionMaintainer* currentRegionMaintainer) { m_currentRegionMaintainer = currentRegionMaintainer; }
     232    RenderRegion* currentRegion() const;
    227233
    228234    ContainingRegionMap& containingRegionMap();
     
    354360    RegionIntervalTree m_regionIntervalTree;
    355361
     362    CurrentRenderRegionMaintainer* m_currentRegionMaintainer;
     363
    356364    bool m_regionsInvalidated : 1;
    357365    bool m_regionsHaveUniformLogicalWidth : 1;
  • trunk/Source/WebCore/rendering/RenderNamedFlowFragment.cpp

    r166867 r167930  
    525525}
    526526
     527void RenderNamedFlowFragment::absoluteQuadsForBoxInRegion(Vector<FloatQuad>& quads, bool* wasFixed, const RenderBox* renderer, float localTop, float localBottom)
     528{
     529    LayoutRect layoutLocalRect(0, localTop, renderer->borderBoxRectInRegion(this).width(), localBottom - localTop);
     530    LayoutRect fragmentRect = rectFlowPortionForBox(renderer, layoutLocalRect);
     531
     532    // We want to skip the 0px height fragments for non-empty boxes that may appear in case the bottom of the box
     533    // overlaps the bottom of a region.
     534    if (localBottom != localTop && !fragmentRect.height())
     535        return;
     536
     537    CurrentRenderRegionMaintainer regionMaintainer(*this);
     538    quads.append(renderer->localToAbsoluteQuad(FloatRect(fragmentRect), 0 /* mode */, wasFixed));
     539}
     540
    527541} // namespace WebCore
  • trunk/Source/WebCore/rendering/RenderNamedFlowFragment.h

    r166781 r167930  
    117117    void updateRegionFlags();
    118118
     119    virtual void absoluteQuadsForBoxInRegion(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) override;
     120
    119121private:
    120122    virtual const char* renderName() const override { return "RenderNamedFlowFragment"; }
  • trunk/Source/WebCore/rendering/RenderNamedFlowThread.cpp

    r167707 r167930  
    840840}
    841841
    842 }
     842bool RenderNamedFlowThread::absoluteQuadsForBox(Vector<FloatQuad>& quads, bool* wasFixed, const RenderBox* renderer, float localTop, float localBottom) const
     843{
     844    RenderRegion* startRegion = nullptr;
     845    RenderRegion* endRegion = nullptr;
     846    // If the box doesn't have a range, we don't know how it is fragmented so fallback to the default behaviour.
     847    if (!getRegionRangeForBox(renderer, startRegion, endRegion))
     848        return false;
     849
     850    for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
     851        RenderRegion* region = *iter;
     852
     853        region->absoluteQuadsForBoxInRegion(quads, wasFixed, renderer, localTop, localBottom);
     854
     855        if (region == endRegion)
     856            break;
     857    }
     858
     859    return true;
     860}
     861
     862}
  • trunk/Source/WebCore/rendering/RenderNamedFlowThread.h

    r167707 r167930  
    100100    void setDispatchRegionOversetChangeEvent(bool value) { m_dispatchRegionOversetChangeEvent = value; }
    101101
     102    virtual bool absoluteQuadsForBox(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) const override;
     103
    102104protected:
    103105    void setMarkForDestruction();
  • trunk/Source/WebCore/rendering/RenderRegion.cpp

    r167810 r167930  
    484484    }
    485485
    486     return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
     486    return m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
    487487}
    488488
     
    574574}
    575575
     576CurrentRenderRegionMaintainer::CurrentRenderRegionMaintainer(RenderRegion& region)
     577    : m_region(region)
     578{
     579    RenderFlowThread* flowThread = region.flowThread();
     580    // A flow thread can have only one current region.
     581    ASSERT(!flowThread->currentRegion());
     582    flowThread->setCurrentRegionMaintainer(this);
     583}
     584
     585CurrentRenderRegionMaintainer::~CurrentRenderRegionMaintainer()
     586{
     587    RenderFlowThread* flowThread = m_region.flowThread();
     588    flowThread->setCurrentRegionMaintainer(nullptr);
     589}
     590
    576591} // namespace WebCore
  • trunk/Source/WebCore/rendering/RenderRegion.h

    r167803 r167930  
    129129    virtual bool hasAutoLogicalHeight() const { return false; }
    130130
     131    virtual void absoluteQuadsForBoxInRegion(Vector<FloatQuad>&, bool*, const RenderBox*, float, float) { }
     132
    131133protected:
    132134    RenderRegion(Element&, PassRef<RenderStyle>, RenderFlowThread*);
     
    180182RENDER_OBJECT_TYPE_CASTS(RenderRegion, isRenderRegion())
    181183
     184class CurrentRenderRegionMaintainer {
     185    WTF_MAKE_NONCOPYABLE(CurrentRenderRegionMaintainer);
     186public:
     187    CurrentRenderRegionMaintainer(RenderRegion&);
     188    ~CurrentRenderRegionMaintainer();
     189
     190    RenderRegion& region() const { return m_region; }
     191private:
     192    RenderRegion& m_region;
     193};
     194
    182195} // namespace WebCore
    183196
Note: See TracChangeset for help on using the changeset viewer.