青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-80  評論-22  文章-0  trackbacks-0
WebKit 在渲染頁面之前,需要確定各個元素的位置、大小,而這個過程就是layout(布局)。下面,我們對layout的主要過程進行一番說明。

一、FrameView::layout方法

FrameView作為與View相關的類,其主要涉及與顯示相關的內容,而其中對頁面元素的布局至關重要,這也是瀏覽器的核心處理部分。

我們都知道瀏覽器從Web服務器獲得數據后,經解析會構建DOM樹、Render樹,然后進行布局處理,進而為渲染頁面作好準備,其中的布局處理往往由FrameView::layout方法發起,讓我們來具體看看其實現,一窺其主要實現過程。

void FrameView::layout(bool allowSubtree)
{
    if (m_midLayout)
      return;

    // Always ensure our style info is up-to-date. This can happen in situations where the layout beats any sort of style recalc update that needs to occur.

    // 進行CSSStyleSelector的更新處理,因為一旦CSS發生變化,布局的結果也可能 發生相關變化,所以在開始布局之前,需要檢查CSS是否發生變化,如果有則需要作相應調整,進而可能影響Render樹等。

    if (m_frame->needsReapplyStyles())
       m_frame->reapplyStyles();
    else if (document->childNeedsStyleRecalc())
       document->recalcStyle();

    bool subtree = m_layoutRoot;
    RenderObject* root = subtree ? m_layoutRoot : document->renderer();
    if (!root) {
        // FIXME: Do we need to set m_size here?
        m_layoutSchedulingEnabled = true;
        return;
    }

    //布局的處理可能相互嵌套,這與發起布局處理的時機相關。
    //設置滾動條相關
    if (m_canHaveScrollbars) {
        hMode = ScrollbarAuto;
        vMode = ScrollbarAuto;
    } else {
        hMode = ScrollbarAlwaysOff;
        vMode = ScrollbarAlwaysOff;
    }

    if (!subtree) {
        // Now set our scrollbar state for the layout.

        if (body->hasTagName(framesetTag) && !m_frame->settings()->frameFlatteningEnabled()) {
            // frameset 而且設置了frameFlatteningEnabled,則關閉滾動條
                body->renderer()->setChildNeedsLayout(true);
                vMode = ScrollbarAlwaysOff;
                hMode = ScrollbarAlwaysOff;
            } else if (body->hasTagName(bodyTag)) {
                // 設置滾動條
                applyOverflowToViewport(o, hMode, vMode);
            }
    }

    //root往往為RenderView對象
    RenderLayer* layer = root->enclosingLayer();

    m_midLayout = true;
    beginDeferredRepaints();
    root->layout();
    endDeferredRepaints();
    m_midLayout = false;

    m_layoutSchedulingEnabled = true;

    if (!subtree && !static_cast(root)->printing())
        adjustViewSize();

    // Now update the positions of all layers.
    //對當前Render樹布局完后,設置RenderLayer樹的布局信息,其中m_doFullRepaint描述是否需要發起渲染處理。

   beginDeferredRepaints();
   layer->updateLayerPositions(...);
   endDeferredRepaints();

    // 設置快速blit
    setCanBlitOnScroll(!useSlowRepaints());

    //因為在布局的過程中,可能進一步獲得網頁數據,則需要繼續布局處理。
    if (!m_postLayoutTasksTimer.isActive()) {
        // Calls resumeScheduledEvents()
        performPostLayoutTasks();

        if (!m_postLayoutTasksTimer.isActive() && needsLayout()) {
            // Post-layout widget updates or an event handler made us need layout again. Lay out again, but this time defer widget updates and event dispatch until after we return.
            m_postLayoutTasksTimer.startOneShot(0);
            pauseScheduledEvents();
            layout();
        }
    } else {
        resumeScheduledEvents();
    }
}


FrameView::layout方法,簡單的說來就是發起對Render樹中的每一個節點按照從父節點到子節點的方式進行x、y、width、height計算,當每一個樹節點的位置及大小確定之后就可以進行后面的渲染。

FrameView::layout往往會調用Render樹根的layout方法即RenderView::layout。


二、RenderView::layout方法

void RenderView::layout()
{
     if (printing())
         m_minPrefWidth = m_maxPrefWidth = m_width;

     // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
     bool relayoutChildren = !printing() && (!m_frameView || m_width != viewWidth() || m_height != viewHeight());
     if (relayoutChildren) {

        setChildNeedsLayout(true, false);
        for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
            if (child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent())
                child->setChildNeedsLayout(true, false);
        }


     }

     ASSERT(!m_layoutState);
     LayoutState state;
     // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
     state.m_clipped = false;
     m_layoutState = &state;

     if (needsLayout())
         RenderBlock::layout();//類繼承的好處,直接調用父類的layout

    // Reset overflow and then replace it with docWidth and docHeight.
    m_overflow.clear();
    addLayoutOverflow(IntRect(0, 0, docWidth(), docHeight()));

     ASSERT(m_layoutStateDisableCount == 0);
     ASSERT(m_layoutState == &state);
     m_layoutState = 0;
     setNeedsLayout(false);
}

void RenderBlock::layout()
{
     // Update our first letter info now.
     updateFirstLetter();
     // Table cells call layoutBlock directly, so don't add any logic here. Put code into layoutBlock().
     layoutBlock(false);

     // It's safe to check for control clip here, since controls can never be table cells. If we have a lightweight clip, there can never be any overflow from children.
    if (hasControlClip() && m_overflow)
        clearLayoutOverflow();
}



三、RenderBlock::layoutBlock方法

layoutBlock 會分成兩個分支:layoutInlineChildren 和 layoutBlockChildren

void RenderBlock::layoutBlock(bool relayoutChildren)
{
    ...
    calcWidth();//先計算寬度
    calcColumnWidth();
   


    m_overflow.clear();   


    if (oldWidth != width() || oldColumnWidth != desiredColumnWidth())
        relayoutChildren = true;
    clearFloats();

    int previousHeight = height();
    setHeight(0);

     //這就是在布局基本概念中提到的Block-level元素的子節點要么是Block-level元素要么為Inline-level元素。
     if (childrenInline())
         layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
     else
         layoutBlockChildren(relayoutChildren, maxFloatBottom);

     // Expand our intrinsic height to encompass floats.
     int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
     if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() ||
(parent() && parent()->isFlexibleBox() || m_hasColumns)))
     setHeight(floatBottom() + toAdd);

     // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as we adjust for clean column breaks.
     int singleColumnBottom = layoutColumns();

     // Calculate our new height.//布局完子節點后確定父節點高度
     int oldHeight = height();
     calcHeight();

     if (previousHeight != height())
         relayoutChildren = true;




     //另外布局屬性為Fixed和absolute的元素
     layoutPositionedObjects(relayoutChildren || isRoot());


     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if we overflow or not.
    updateScrollInfoAfterLayout();


    // Repaint with our new bounds if they are different from our old bounds.
    bool didFullRepaint = repainter.repaintAfterLayout();
    if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
        // 設置repaintRect


       // Make sure the rect is still non-empty after intersecting for overflow above
        if (!repaintRect.isEmpty()) {
            repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
            if (hasReflection())
                repaintRectangle(reflectedRect(repaintRect));
        }
    }
    setNeedsLayout(false);
}


四、RenderBlock::layoutBlockChildren方法


void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom)
{
int top = borderTop() + paddingTop();
int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();





    // Fieldsets need to find their legend and position it inside the border of the object.
    // The legend then gets skipped during normal layout.
    RenderObject* legend = layoutLegend(relayoutChildren);



//遍歷子節點

RenderBox* next = firstChildBox();
    while (next) {
        RenderBox* child = next;
        next = child->nextSiblingBox();

        if (legend == child)
            continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
       // Make sure we layout children if they need it.
        // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
        // an auto value.  Add a method to determine this, so that we can avoid the relayout.
        if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView()))
            child->setChildNeedsLayout(true, false);

        // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
        if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent()))
            child->setPrefWidthsDirty(true, false);

        // Handle the four types of special elements first.  These include positioned content, floating content, compacts and
        // run-ins.  When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
        if (handleSpecialChild(child, marginInfo))
            continue;

        // Lay out the child.
        layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom);
    }

    // Now do the handling of the bottom of the block, adding in our bottom border/padding and
    // determining the correct collapsed bottom margin information.
    handleBottomOfBlock(top, bottom, marginInfo);
}

layoutBlockChild 方法就比較復雜了,具體可以自己看代碼。


五、RenderBlock::layoutInlineChildren方法

這個方法相當復雜,其作用就是布局文字、圖像等,對文字行高確定、斷行等處理,同時還包括 文字從左到右或從右到左的布局處理。具體可以參考bidi.cpp中的源碼實現。


六、調用FrameView::layout方法的時機

由于從Web服務器獲取的網頁數據不可能一次性完成,往往需要邊獲取數據,邊布局,然后渲染,這樣才可能獲得良好的用戶感受。

所以一旦獲得主要數據如css數據及body等標簽后,就可以開始布局,布局完后會根據當前條件決定是否將布局的數據渲染出來,或者繼續布局處理后來獲取的數據,這樣也增加了布局處理過程的復雜度。

而調用layout方法的時機也至關重要,因為layout本身就可能需要花費大量的時間如layoutBlockChildren、 layoutInlineChildren等處理,其往往與網頁的內容有關,而網頁的內容卻由網頁開發者來確定,對瀏覽器來講是千變萬化的,這就對 layout方法的實現及調用時機提出更高的要求,同時確定了其復雜性。

調用layout的時機主要有獲得一定DOM文檔數據后調用Document::updateLayout()、需要重新使用CSS數據時調用Document::recalcStyle()、改變窗口大小后調用Frame::forceLayout()等來實現。。。


七、總結

其實WebKit涉及網頁布局方面的layout方法蠻復雜的,如其他RenderObject子類也會根據自身情況重載實現layout,還有對float、fixed、absolute、inline元素等的處理,但其主要邏輯就象上面所提,這里只是匯總一下主要流程及概念,針對每一個具體標簽或RenderObject的布局實現則需要更深一步的了解,希望大家能對了解WebKit的網頁布局過程有一個清晰而準確的認識。。
posted on 2012-04-23 17:35 Bluesea 閱讀(2259) 評論(0)  編輯 收藏 引用 所屬分類: Android-WebKit
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美大片免费观看| 亚洲一区二区四区| 国产亚洲欧美色| 亚洲久久视频| 看片网站欧美日韩| 亚洲一区在线免费观看| 欧美片网站免费| 亚洲日本成人在线观看| 牛牛影视久久网| 久久久国产精品一区二区中文 | 久久精品在线免费观看| 国产日韩欧美在线播放| 午夜亚洲伦理| 亚洲性夜色噜噜噜7777| 国产精品高潮久久| 亚洲先锋成人| 日韩视频第一页| 欧美另类一区二区三区| 一本色道久久88综合日韩精品 | 最新中文字幕一区二区三区| 欧美一区国产二区| 一区在线播放| 欧美国产一区二区| 欧美极品一区| 亚洲专区一区| 欧美在线|欧美| 在线观看成人av电影| 欧美成人一区二区| 欧美激情网站在线观看| 亚洲小视频在线观看| 亚洲性夜色噜噜噜7777| 国产一区91| 免费成人美女女| 久久久亚洲成人| 亚洲天堂av电影| 性视频1819p久久| 亚洲高清中文字幕| 亚洲三级国产| 国产欧美一区二区三区国产幕精品| 久久久久久久网| 欧美成黄导航| 午夜影院日韩| 老司机久久99久久精品播放免费 | 亚洲国产日韩欧美在线99| 欧美激情综合五月色丁香| 在线亚洲美日韩| 久久丁香综合五月国产三级网站| 亚洲精品小视频在线观看| 看欧美日韩国产| 欧美人与性动交α欧美精品济南到| 亚洲桃花岛网站| 久久国产精品久久精品国产 | 欧美成人免费视频| 欧美日本精品一区二区三区| 羞羞漫画18久久大片| 久久久久久自在自线| 日韩一区二区久久| 欧美中文在线免费| 在线综合视频| 久久久噜噜噜久久人人看| 亚洲手机成人高清视频| 久久av一区二区三区亚洲| 99成人在线| 久久精品视频在线| 亚洲砖区区免费| 欧美国产激情| 欧美中文字幕第一页| 欧美风情在线| 久久综合伊人77777麻豆| 欧美色综合天天久久综合精品| 久久久久久久一区二区| 欧美无乱码久久久免费午夜一区| 欧美顶级少妇做爰| 国产一区二区三区精品久久久| 99av国产精品欲麻豆| 91久久久久久| 久久久久亚洲综合| 久久激情五月婷婷| 国产精品www色诱视频| 亚洲国产精品高清久久久| 国模精品一区二区三区| 亚洲欧美精品伊人久久| 亚洲男女毛片无遮挡| 欧美日韩激情网| 亚洲激情一区| 亚洲人午夜精品| 六月婷婷一区| 欧美a级一区| 国产一区二区视频在线观看| 亚洲已满18点击进入久久| 一区二区三区欧美日韩| 欧美日本中文| 亚洲乱码国产乱码精品精| 一本到高清视频免费精品| 欧美好吊妞视频| 亚洲欧洲日韩在线| 99国产精品久久久久老师| 欧美大胆人体视频| 亚洲国产99| 亚洲最新中文字幕| 国产精品jizz在线观看美国 | 一个人看的www久久| 亚洲看片免费| 欧美久久一区| 99精品欧美一区二区三区| 亚洲午夜av在线| 国产精品免费一区二区三区观看| 亚洲视频大全| 欧美一区三区二区在线观看| 国产精品色午夜在线观看| 销魂美女一区二区三区视频在线| 国产精品一区二区在线| 亚洲欧美国产精品va在线观看| 性久久久久久久| 国产自产v一区二区三区c| 久久久最新网址| 亚洲高清三级视频| 中文日韩在线视频| 国产麻豆一精品一av一免费| 久久久久综合一区二区三区| 亚洲高清视频一区| 亚洲女性裸体视频| 国内精品久久久| 欧美福利影院| 亚洲一区二区三区欧美| 久久久精品网| 亚洲美女电影在线| 国产精品视频1区| 久久久久久久91| 亚洲美女少妇无套啪啪呻吟| 午夜视频一区在线观看| 一区二区三区在线观看视频| 欧美精品国产精品| 欧美一级播放| 亚洲精品影院| 久久综合国产精品台湾中文娱乐网| 亚洲国产一区在线观看| 国产精品男女猛烈高潮激情| 久久在线视频| 亚洲一区区二区| 欧美激情第10页| 久久国产乱子精品免费女| 亚洲日本成人| 国产婷婷色一区二区三区四区| 欧美丰满高潮xxxx喷水动漫| 欧美一区永久视频免费观看| 亚洲精品在线三区| 欧美a级在线| 欧美在线观看一二区| 亚洲三级国产| 国内精品一区二区三区| 欧美日韩亚洲一区二区三区| 欧美一区二区三区视频在线| 亚洲欧洲中文日韩久久av乱码| 欧美专区18| 亚洲视频在线观看一区| 亚洲国产一区二区三区在线播 | 中文日韩电影网站| 亚洲国产精品日韩| 国产亚洲精品久久久久动| 欧美日韩在线观看一区二区| 麻豆精品视频在线观看| 久久成人精品电影| 亚洲欧美视频在线| 亚洲无亚洲人成网站77777| 亚洲人成77777在线观看网| 久久综合色影院| 久久久久久自在自线| 欧美一区二区三区精品电影| 亚洲一二三区在线观看| 亚洲精选一区| 亚洲精品欧洲| 99这里只有精品| 亚洲精品国产无天堂网2021| 在线欧美日韩国产| 精品电影一区| 在线观看精品视频| 韩国av一区| 在线观看亚洲视频啊啊啊啊| 国产一区二区三区在线观看免费视频| 国产精品家教| 国产精品久久一区主播| 国产精品v欧美精品∨日韩| 国产精品久久国产精品99gif| 欧美日韩一区三区| 亚洲日本中文字幕区| 久色婷婷小香蕉久久| 另类欧美日韩国产在线| 欧美aa国产视频| 亚洲第一页中文字幕| 亚洲国产精品一区二区第四页av| 亚洲福利视频专区| 亚洲裸体视频| 中文日韩在线| 性欧美长视频| 久久婷婷激情| 欧美成人午夜免费视在线看片| 欧美成人dvd在线视频| 欧美精品一区二区精品网| 欧美特黄视频|