Changeset 105176 in webkit


Ignore:
Timestamp:
Jan 17, 2012 11:16:24 AM (12 years ago)
Author:
hyatt@apple.com
Message:

Source/WebCore: https://bugs.webkit.org/show_bug.cgi?id=76197

Implementation of baseline grid alignment. This patch implements line grid tracking in the layout state,
and also implements the snapping of lines to baselines. It works with normal flow, positioning and floats and
with pagination, as long as the grid is inside the pagination context and not outside.

Reviewed by Simon Fraser.

Added a bunch of new tests in fast/line-grid.

  • WebCore.xcodeproj/project.pbxproj:
  • rendering/InlineFlowBox.h:

(WebCore::InlineFlowBox::setHasTextChildren):

  • rendering/LayoutState.cpp:

(WebCore::LayoutState::LayoutState):
(WebCore::LayoutState::propagateLineGridInfo):
(WebCore::LayoutState::establishLineGrid):

  • rendering/LayoutState.h:

(WebCore::LayoutState::LayoutState):
(WebCore::LayoutState::pageLogicalHeight):
(WebCore::LayoutState::currentLineGrid):
(WebCore::LayoutState::currentLineGridOffset):
(WebCore::LayoutState::layoutOffset):
(WebCore::LayoutState::needsBlockDirectionLocationSetBeforeLayout):

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::layoutBlockChildren):
(WebCore::RenderBlock::layoutPositionedObjects):
(WebCore::RenderBlock::insertFloatingObject):
(WebCore::RenderBlock::positionNewFloats):
(WebCore::RenderBlock::pageLogicalTopForOffset):
(WebCore::RenderBlock::adjustLinePositionForPagination):

  • rendering/RenderBlock.h:

(WebCore::RenderBlock::lineGridBox):
(WebCore::RenderBlock::setLineGridBox):
(WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):

  • rendering/RenderBlockLineLayout.cpp:

(WebCore::RenderBlock::layoutInlineChildren):
(WebCore::RenderBlock::layoutLineGridBox):

  • rendering/RenderFlowThread.cpp:

(WebCore::RenderFlowThread::regionLogicalTopForLine):

  • rendering/RenderFlowThread.h:
  • rendering/RenderView.h:

(WebCore::RenderView::pushLayoutState):

  • rendering/RootInlineBox.cpp:

(WebCore::RootInlineBox::alignBoxesInBlockDirection):
(WebCore::RootInlineBox::lineGridSnapAdjustment):

  • rendering/RootInlineBox.h:

LayoutTests: https://bugs.webkit.org/show_bug.cgi?id=76197

Add tests for baseline line grid alignment.

Reviewed by Simon Fraser.

  • fast/line-grid/line-grid-floating.html: Added.
  • fast/line-grid/line-grid-inside-columns.html: Added.
  • fast/line-grid/line-grid-into-floats.html: Added.
  • fast/line-grid/line-grid-positioned.html: Added.
  • platform/mac/fast/line-grid: Added.
  • platform/mac/fast/line-grid/line-grid-floating-expected.png: Added.
  • platform/mac/fast/line-grid/line-grid-floating-expected.txt: Added.
  • platform/mac/fast/line-grid/line-grid-inside-columns-expected.png: Added.
  • platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt: Added.
  • platform/mac/fast/line-grid/line-grid-into-floats-expected.png: Added.
  • platform/mac/fast/line-grid/line-grid-into-floats-expected.txt: Added.
  • platform/mac/fast/line-grid/line-grid-positioned-expected.png: Added.
  • platform/mac/fast/line-grid/line-grid-positioned-expected.txt: Added.
Location:
trunk
Files:
13 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r105172 r105176  
     12012-01-12  David Hyatt  <hyatt@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=76197
     4       
     5        Add tests for baseline line grid alignment.
     6
     7        Reviewed by Simon Fraser.
     8
     9        * fast/line-grid/line-grid-floating.html: Added.
     10        * fast/line-grid/line-grid-inside-columns.html: Added.
     11        * fast/line-grid/line-grid-into-floats.html: Added.
     12        * fast/line-grid/line-grid-positioned.html: Added.
     13        * platform/mac/fast/line-grid: Added.
     14        * platform/mac/fast/line-grid/line-grid-floating-expected.png: Added.
     15        * platform/mac/fast/line-grid/line-grid-floating-expected.txt: Added.
     16        * platform/mac/fast/line-grid/line-grid-inside-columns-expected.png: Added.
     17        * platform/mac/fast/line-grid/line-grid-inside-columns-expected.txt: Added.
     18        * platform/mac/fast/line-grid/line-grid-into-floats-expected.png: Added.
     19        * platform/mac/fast/line-grid/line-grid-into-floats-expected.txt: Added.
     20        * platform/mac/fast/line-grid/line-grid-positioned-expected.png: Added.
     21        * platform/mac/fast/line-grid/line-grid-positioned-expected.txt: Added.
     22
    1232012-01-17  Tim Horton  <timothy_horton@apple.com>
    224
  • trunk/Source/WebCore/ChangeLog

    r105172 r105176  
     12012-01-12  David Hyatt  <hyatt@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=76197
     4       
     5        Implementation of baseline grid alignment. This patch implements line grid tracking in the layout state,
     6        and also implements the snapping of lines to baselines. It works with normal flow, positioning and floats and
     7        with pagination, as long as the grid is inside the pagination context and not outside.
     8
     9        Reviewed by Simon Fraser.
     10
     11        Added a bunch of new tests in fast/line-grid.
     12
     13        * WebCore.xcodeproj/project.pbxproj:
     14        * rendering/InlineFlowBox.h:
     15        (WebCore::InlineFlowBox::setHasTextChildren):
     16        * rendering/LayoutState.cpp:
     17        (WebCore::LayoutState::LayoutState):
     18        (WebCore::LayoutState::propagateLineGridInfo):
     19        (WebCore::LayoutState::establishLineGrid):
     20        * rendering/LayoutState.h:
     21        (WebCore::LayoutState::LayoutState):
     22        (WebCore::LayoutState::pageLogicalHeight):
     23        (WebCore::LayoutState::currentLineGrid):
     24        (WebCore::LayoutState::currentLineGridOffset):
     25        (WebCore::LayoutState::layoutOffset):
     26        (WebCore::LayoutState::needsBlockDirectionLocationSetBeforeLayout):
     27        * rendering/RenderBlock.cpp:
     28        (WebCore::RenderBlock::layoutBlockChildren):
     29        (WebCore::RenderBlock::layoutPositionedObjects):
     30        (WebCore::RenderBlock::insertFloatingObject):
     31        (WebCore::RenderBlock::positionNewFloats):
     32        (WebCore::RenderBlock::pageLogicalTopForOffset):
     33        (WebCore::RenderBlock::adjustLinePositionForPagination):
     34        * rendering/RenderBlock.h:
     35        (WebCore::RenderBlock::lineGridBox):
     36        (WebCore::RenderBlock::setLineGridBox):
     37        (WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):
     38        * rendering/RenderBlockLineLayout.cpp:
     39        (WebCore::RenderBlock::layoutInlineChildren):
     40        (WebCore::RenderBlock::layoutLineGridBox):
     41        * rendering/RenderFlowThread.cpp:
     42        (WebCore::RenderFlowThread::regionLogicalTopForLine):
     43        * rendering/RenderFlowThread.h:
     44        * rendering/RenderView.h:
     45        (WebCore::RenderView::pushLayoutState):
     46        * rendering/RootInlineBox.cpp:
     47        (WebCore::RootInlineBox::alignBoxesInBlockDirection):
     48        (WebCore::RootInlineBox::lineGridSnapAdjustment):
     49        * rendering/RootInlineBox.h:
     50
    1512012-01-17  Tim Horton  <timothy_horton@apple.com>
    252
  • trunk/Source/WebCore/rendering/InlineFlowBox.h

    r103772 r105176  
    193193    bool hasTextChildren() const { return m_hasTextChildren; }
    194194    bool hasTextDescendants() const { return m_hasTextDescendants; }
     195    void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); }
    195196    void setHasTextDescendants() { m_hasTextDescendants = true; }
    196 
     197   
    197198    void checkConsistency() const;
    198199    void setHasBadChildList();
  • trunk/Source/WebCore/rendering/LayoutState.cpp

    r103243 r105176  
    3838LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo)
    3939    : m_columnInfo(columnInfo)
     40    , m_currentLineGrid(0)
    4041    , m_next(prev)
    4142#ifndef NDEBUG
     
    108109   
    109110    m_isPaginated = m_pageLogicalHeight || m_columnInfo;
    110    
     111
     112    // Propagate line grid information.
     113    propagateLineGridInfo(renderer);
     114
     115    // If we have a new grid to track, then add it to our set.
     116    if (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow())
     117        establishLineGrid(toRenderBlock(renderer));
     118
    111119    // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
    112120}
     
    118126    , m_pageLogicalHeightChanged(regionsChanged)
    119127    , m_columnInfo(0)
     128    , m_currentLineGrid(0)
    120129    , m_next(prev)
    121130#ifndef NDEBUG
     
    134143    , m_pageLogicalHeightChanged(false)
    135144    , m_columnInfo(0)
     145    , m_currentLineGrid(0)
    136146    , m_next(0)
    137147#ifndef NDEBUG
     
    197207}
    198208
     209void LayoutState::propagateLineGridInfo(RenderBox* renderer)
     210{
     211    // Disable line grids for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and
     212    // writing mode roots.
     213    if (!m_next || renderer->isUnsplittableForPagination())
     214        return;
     215
     216    m_currentLineGrid = m_next->m_currentLineGrid;
     217    m_currentLineGridOffset = m_next->m_currentLineGridOffset;
     218}
     219
     220void LayoutState::establishLineGrid(RenderBlock* block)
     221{
     222    // First check to see if this grid has been established already.
     223    if (m_currentLineGrid) {
     224        if (m_currentLineGrid->style()->lineGrid() == block->style()->lineGrid())
     225            return;
     226        RenderBlock* currentGrid = m_currentLineGrid;
     227        for (LayoutState* currentState = m_next; currentState; currentState = currentState->m_next) {
     228            if (currentState->m_currentLineGrid == currentGrid)
     229                continue;
     230            currentGrid = currentState->m_currentLineGrid;
     231            if (currentGrid->style()->lineGrid() == block->style()->lineGrid()) {
     232                m_currentLineGrid = currentGrid;
     233                m_currentLineGridOffset = currentState->m_currentLineGridOffset;
     234                return;
     235            }
     236        }
     237    }
     238   
     239    // We didn't find an already-established grid with this identifier. Our render object establishes the grid.
     240    m_currentLineGrid = block;
     241    m_currentLineGridOffset = m_layoutOffset;
     242}
     243
    199244} // namespace WebCore
  • trunk/Source/WebCore/rendering/LayoutState.h

    r103243 r105176  
    2828
    2929#include "LayoutTypes.h"
     30#include <wtf/HashMap.h>
    3031#include <wtf/Noncopyable.h>
    3132
     
    3435class ColumnInfo;
    3536class RenderArena;
     37class RenderBlock;
    3638class RenderBox;
    3739class RenderObject;
     
    4749        , m_pageLogicalHeightChanged(false)
    4850        , m_columnInfo(0)
     51        , m_currentLineGrid(0)
    4952        , m_next(0)
    5053#ifndef NDEBUG
     
    7679    void addForcedColumnBreak(LayoutUnit childLogicalOffset);
    7780   
    78     bool pageLogicalHeight() const { return m_pageLogicalHeight; }
     81    LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; }
    7982    bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; }
     83
     84    RenderBlock* currentLineGrid() const { return m_currentLineGrid; }
     85    LayoutSize currentLineGridOffset() const { return m_currentLineGridOffset; }
     86
     87    LayoutSize layoutOffset() const { return m_layoutOffset; }
     88
     89    bool needsBlockDirectionLocationSetBeforeLayout() const { return m_currentLineGrid || (m_isPaginated && m_pageLogicalHeight); }
    8090
    8191private:
    8292    // The normal operator new is disallowed.
    8393    void* operator new(size_t) throw();
     94
     95    void propagateLineGridInfo(RenderBox*);
     96    void establishLineGrid(RenderBlock*);
    8497
    8598public:
     
    106119    ColumnInfo* m_columnInfo;
    107120
     121    // The current line grid that we're snapping to and the offset of the start of the grid.
     122    RenderBlock* m_currentLineGrid;
     123    LayoutSize m_currentLineGridOffset;
     124   
    108125    LayoutState* m_next;
    109126#ifndef NDEBUG
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r105120 r105176  
    198198
    199199    m_lineBoxes.deleteLineBoxes(renderArena());
     200
     201    if (lineGridBox())
     202        lineGridBox()->destroy(renderArena());
    200203
    201204    if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
     
    19881991
    19891992    setLogicalHeight(beforeEdge);
     1993   
     1994    // Lay out our hypothetical grid line as though it occurs at the top of the block.
     1995    if (view()->layoutState()->currentLineGrid() == this)
     1996        layoutLineGridBox();
    19901997
    19911998    // The margin struct caches all our current margin collapsing state.  The compact struct caches state when we encounter compacts,
     
    23022309            r->setNeedsLayout(false);
    23032310           
    2304         // If we are in a flow thread, go ahead and compute a vertical position for our object now.
     2311        // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
    23052312        // If it's wrong we'll lay out again.
    23062313        LayoutUnit oldLogicalTop = 0;
    2307         bool checkForPaginationRelayout = r->needsLayout() && view()->layoutState()->isPaginated() && view()->layoutState()->pageLogicalHeight();
    2308         if (checkForPaginationRelayout) {
     2314        bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
     2315        if (needsBlockDirectionLocationSetBeforeLayout) {
    23092316            if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
    23102317                r->computeLogicalHeight();
     
    23172324       
    23182325        // Lay out again if our estimate was wrong.
    2319         if (checkForPaginationRelayout && logicalTopForChild(r) != oldLogicalTop) {
     2326        if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) {
    23202327            r->setChildNeedsLayout(true, false);
    23212328            r->layoutIfNeeded();
     
    33083315            o->setChildNeedsLayout(true, false);
    33093316           
    3310         bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageLogicalHeight;
    3311         if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
     3317        bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
     3318        if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
    33123319            o->layoutIfNeeded();
    33133320        else {
     
    34893496        setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
    34903497
    3491         if (view()->layoutState()->isPaginated()) {
    3492             RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
    3493 
    3494             if (!childBox->needsLayout())
    3495                 childBox->markForPaginationRelayoutIfNeeded();
    3496             childBox->layoutIfNeeded();
    3497 
     3498        LayoutState* layoutState = view()->layoutState();
     3499        bool isPaginated = layoutState->isPaginated();
     3500        if (isPaginated && !childBox->needsLayout())
     3501            childBox->markForPaginationRelayoutIfNeeded();
     3502       
     3503        childBox->layoutIfNeeded();
     3504
     3505        if (isPaginated) {
    34983506            // If we are unsplittable and don't fit, then we need to move down.
    34993507            // We include our margins as part of the unsplittable area.
     
    35033511            // Note that an unsplittable child can't also have a pagination strut, so this is
    35043512            // exclusive with the case above.
     3513            RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
    35053514            if (childBlock && childBlock->paginationStrut()) {
    35063515                newLogicalTop += childBlock->paginationStrut();
     
    63916400    }
    63926401    return logicalOffset;
     6402}
     6403
     6404LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
     6405{
     6406    RenderView* renderView = view();
     6407    LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
     6408    LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
     6409
     6410    LayoutUnit cumulativeOffset = offset + blockLogicalTop;
     6411    if (!inRenderFlowThread()) {
     6412        LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
     6413        if (!pageLogicalHeight)
     6414            return 0;
     6415        return cumulativeOffset - (cumulativeOffset - firstPageLogicalTop) % pageLogicalHeight;
     6416    }
     6417    return enclosingRenderFlowThread()->regionLogicalTopForLine(cumulativeOffset);
    63936418}
    63946419
     
    65076532            lineBox->setPaginationStrut(remainingLogicalHeight);
    65086533        }
    6509     } 
     6534    }
    65106535}
    65116536
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r105120 r105176  
    240240    void setPageLogicalOffset(int);
    241241
     242    RootInlineBox* lineGridBox() const { return m_rareData ? m_rareData->m_lineGridBox : 0; }
     243    void setLineGridBox(RootInlineBox* box)
     244    {
     245        if (!m_rareData)
     246            m_rareData = adoptPtr(new RenderBlockRareData(this));
     247        if (m_rareData->m_lineGridBox)
     248            m_rareData->m_lineGridBox->destroy(renderArena());
     249        m_rareData->m_lineGridBox = box;
     250    }
     251    void layoutLineGridBox();
     252
    242253    // Accessors for logical width/height and margins in the containing block's block-flow direction.
    243254    enum ApplyLayoutDeltaMode { ApplyLayoutDelta, DoNotApplyLayoutDelta };
     
    472483
    473484    virtual void updateBeforeAfterContent(PseudoId);
    474 
     485   
    475486    virtual RootInlineBox* createRootInlineBox(); // Subclassed by SVG and Ruby.
    476487
     
    896907    LayoutUnit applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column.
    897908
     909public:
     910    LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const;
    898911    LayoutUnit pageLogicalHeightForOffset(LayoutUnit offset) const;
    899912    LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule = IncludePageBoundary) const;
     913   
     914protected:
    900915    bool pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const;
    901916
     
    10181033            , m_paginationStrut(0)
    10191034            , m_pageLogicalOffset(0)
     1035            , m_lineGridBox(0)
    10201036        {
    10211037        }
     
    10401056       
    10411057        MarginValues m_margins;
    1042         int m_paginationStrut;
    1043         int m_pageLogicalOffset;
     1058        LayoutUnit m_paginationStrut;
     1059        LayoutUnit m_pageLogicalOffset;
     1060       
     1061        RootInlineBox* m_lineGridBox;
    10441062     };
    10451063
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r104322 r105176  
    14391439
    14401440    setLogicalHeight(borderBefore() + paddingBefore());
     1441   
     1442    // Lay out our hypothetical grid line as though it occurs at the top of the block.
     1443    if (view()->layoutState() && view()->layoutState()->currentLineGrid() == this)
     1444        layoutLineGridBox();
    14411445
    14421446    // Figure out if we should clear out our line boxes.
     
    27582762}
    27592763
    2760 }
     2764
     2765void RenderBlock::layoutLineGridBox()
     2766{
     2767    if (style()->lineGrid() == RenderStyle::initialLineGrid()) {
     2768        setLineGridBox(0);
     2769        return;
     2770    }
     2771   
     2772    setLineGridBox(0);
     2773
     2774    RootInlineBox* lineGridBox = new (renderArena()) RootInlineBox(this);
     2775    lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
     2776    lineGridBox->setConstructed();
     2777    GlyphOverflowAndFallbackFontsMap textBoxDataMap;
     2778    VerticalPositionCache verticalPositionCache;
     2779    lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
     2780   
     2781    setLineGridBox(lineGridBox);
     2782   
     2783    // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
     2784    // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
     2785    // to this grid.
     2786}
     2787
     2788}
  • trunk/Source/WebCore/rendering/RenderFlowThread.cpp

    r104965 r105176  
    555555}
    556556
     557LayoutUnit RenderFlowThread::regionLogicalTopForLine(LayoutUnit position) const
     558{
     559    RenderRegion* region = renderRegionForLine(position);
     560    if (!region)
     561        return 0;
     562    return isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x();
     563}
     564
    557565LayoutUnit RenderFlowThread::regionLogicalWidthForLine(LayoutUnit position) const
    558566{
  • trunk/Source/WebCore/rendering/RenderFlowThread.h

    r104965 r105176  
    101101    void repaintRectangleInRegions(const LayoutRect&, bool immediate);
    102102
     103    LayoutUnit regionLogicalTopForLine(LayoutUnit position) const;
    103104    LayoutUnit regionLogicalWidthForLine(LayoutUnit position) const;
    104105    LayoutUnit regionLogicalHeightForLine(LayoutUnit position) const;
  • trunk/Source/WebCore/rendering/RenderView.h

    r104965 r105176  
    211211    {
    212212        // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
    213         if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->inRenderFlowThread()) {
     213        if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->inRenderFlowThread()
     214            || m_layoutState->currentLineGrid() || (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow())) {
    214215            m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo);
    215216            return true;
  • trunk/Source/WebCore/rendering/RootInlineBox.cpp

    r97052 r105176  
    3434#include "RenderArena.h"
    3535#include "RenderBlock.h"
     36#include "RenderView.h"
    3637#include "VerticalPositionCache.h"
    3738#include <wtf/unicode/Unicode.h>
     
    286287    }
    287288
     289    LayoutUnit gridSnapAdjustment = lineGridSnapAdjustment();
     290    if (gridSnapAdjustment) {
     291        adjustBlockDirectionPosition(gridSnapAdjustment);
     292        heightOfBlock += gridSnapAdjustment;
     293    }
     294
    288295    return heightOfBlock + maxHeight;
    289296}
     
    318325
    319326    return result;
     327}
     328
     329LayoutUnit RootInlineBox::lineGridSnapAdjustment(LayoutUnit delta) const
     330{
     331    // If our block doesn't have snapping turned on, do nothing.
     332    // FIXME: Implement bounds snapping.
     333    if (block()->style()->lineGridSnap() != LineGridSnapBaseline)
     334        return 0;
     335
     336    // Get the current line grid and offset.
     337    LayoutState* layoutState = block()->view()->layoutState();
     338    RenderBlock* lineGrid = layoutState->currentLineGrid();
     339    LayoutSize lineGridOffset = layoutState->currentLineGridOffset();
     340    if (!lineGrid || lineGrid->style()->writingMode() != block()->style()->writingMode())
     341        return 0;
     342
     343    // Get the hypothetical line box used to establish the grid.
     344    RootInlineBox* lineGridBox = lineGrid->lineGridBox();
     345    if (!lineGridBox)
     346        return 0;
     347   
     348    LayoutUnit lineGridBlockOffset = lineGrid->isHorizontalWritingMode() ? lineGridOffset.height() : lineGridOffset.width();
     349    LayoutUnit blockOffset = block()->isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width();
     350
     351    // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple
     352    // as established by the line box.
     353    // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume
     354    // the grid should honor line-box-contain.
     355    LayoutUnit baselineMultiple = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading();
     356    if (!baselineMultiple)
     357        return 0;
     358
     359    LayoutUnit lineGridAscent = lineGrid->style()->fontMetrics().ascent(baselineType());
     360    LayoutUnit firstBaselinePosition = lineGridBlockOffset + lineGridAscent + lineGridBox->logicalTop();
     361    LayoutUnit currentBaselinePosition = blockOffset + logicalTop() + delta + block()->style()->fontMetrics().ascent(baselineType());
     362
     363    // If we're paginated, see if we're on a page after the first one. If so, the grid resets on subsequent pages.
     364    // FIXME: If the grid is an ancestor of the pagination establisher, then this is incorrect.
     365    LayoutUnit pageLogicalTop = 0;
     366    if (layoutState->isPaginated() && layoutState->pageLogicalHeight()) {
     367        pageLogicalTop = block()->pageLogicalTopForOffset(logicalTop() + delta);
     368        if (pageLogicalTop > lineGridBlockOffset + lineGridBox->logicalTop())
     369            firstBaselinePosition = lineGridAscent + pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderBefore() - lineGrid->paddingBefore();
     370    }
     371           
     372    // If we're above the first line, just push to the first line.
     373    if (currentBaselinePosition < firstBaselinePosition)
     374        return delta + firstBaselinePosition - currentBaselinePosition;
     375
     376    // Otherwise we're in the middle of the grid somewhere. Just push to the next line.
     377    LayoutUnit baselineOffset = currentBaselinePosition - firstBaselinePosition;
     378    LayoutUnit remainder = baselineOffset % baselineMultiple;
     379    LayoutUnit result = delta;
     380    if (remainder)
     381        result += baselineMultiple - remainder;
     382
     383    // If we aren't paginated we can return the result.
     384    if (!layoutState->isPaginated() || !layoutState->pageLogicalHeight() || result == delta)
     385        return result;
     386   
     387    // We may have shifted to a new page. We need to do a re-snap when that happens.
     388    LayoutUnit newPageLogicalTop = block()->pageLogicalTopForOffset(logicalTop() + result);
     389    if (newPageLogicalTop == pageLogicalTop)
     390        return result;
     391   
     392    // Put ourselves at the top of the next page to force a snap onto the new grid established by that page.
     393    return lineGridSnapAdjustment(newPageLogicalTop - (blockOffset + logicalTop()));
    320394}
    321395
  • trunk/Source/WebCore/rendering/RootInlineBox.h

    r97052 r105176  
    177177    Node* getLogicalStartBoxWithNode(InlineBox*&) const;
    178178    Node* getLogicalEndBoxWithNode(InlineBox*&) const;
     179
    179180#ifndef NDEBUG
    180181    virtual const char* boxName() const;
     
    182183private:
    183184    void setHasEllipsisBox(bool hasEllipsisBox) { m_hasEllipsisBoxOrHyphen = hasEllipsisBox; }
     185   
     186    LayoutUnit lineGridSnapAdjustment(LayoutUnit delta = 0) const;
    184187
    185188    int beforeAnnotationsAdjustment() const;
Note: See TracChangeset for help on using the changeset viewer.