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

隨筆-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 閱讀(2252) 評論(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>
            久久一二三区| 亚洲免费观看视频| 久久久久国产免费免费| 国产精品观看| 亚洲与欧洲av电影| 欧美一站二站| 国产精品视频一二三| 午夜精品久久久久久久蜜桃app| 999在线观看精品免费不卡网站| 国产精品99久久久久久久vr| 国产精品午夜国产小视频| 亚洲国产一区二区a毛片| 亚洲午夜激情网站| 欧美成人午夜剧场免费观看| 国产亚洲一区二区在线观看 | 欧美中文在线观看| 欧美在线视频在线播放完整版免费观看 | 国产欧美一区二区色老头| 日韩视频永久免费观看| 欧美不卡在线视频| 欧美高清在线观看| 久久精品视频免费| 嫩草伊人久久精品少妇av杨幂| 在线亚洲精品| 免费久久99精品国产自| 午夜精品久久久久久久白皮肤| 久久久久国产精品www | 欧美激情一区三区| 欧美日韩国产色视频| 亚洲一区二区3| 久久精品三级| 日韩亚洲欧美成人| 亚洲高清在线精品| 亚洲校园激情| 国外成人免费视频| 一本色道久久综合狠狠躁的推荐| 91久久久久久| 午夜在线视频观看日韩17c| 精品成人a区在线观看| 亚洲激情视频| 亚洲二区在线视频| 久久裸体视频| 你懂的国产精品| 国产乱码精品一区二区三区忘忧草 | 久久av一区二区三区| 国产精品一二三| 麻豆成人在线观看| 亚洲网站在线观看| 1204国产成人精品视频| 欧美激情91| 欧美欧美天天天天操| 欧美大片91| 欧美日韩精品一区二区天天拍小说 | 欧美日韩一区二区三区四区五区| 亚洲欧洲综合| 国产欧美视频一区二区| 快射av在线播放一区| 久久精品国产96久久久香蕉| 欧美在线视频不卡| 雨宫琴音一区二区在线| 另类激情亚洲| 香蕉精品999视频一区二区| 中文在线资源观看视频网站免费不卡| 亚洲人成毛片在线播放| 免费观看在线综合色| 欧美成人按摩| 国产精品腿扒开做爽爽爽挤奶网站| 免费观看成人网| 亚洲开发第一视频在线播放| 欧美日韩综合精品| 欧美激情一区三区| 欧美另类亚洲| 国产精品一区二区黑丝| 欧美私人啪啪vps| 国内精品视频一区| 欧美性色综合| 韩国女主播一区| 国产视频久久久久久久| 1024成人网色www| 亚洲国产三级网| 9l国产精品久久久久麻豆| 在线看不卡av| 欧美一级播放| 欧美一区二区观看视频| 久久手机免费观看| 嫩草影视亚洲| 亚洲黄色成人久久久| 久久久青草青青国产亚洲免观| 久久中文字幕一区二区三区| 小嫩嫩精品导航| 亚洲电影视频在线| 亚洲视频综合在线| 久久视频在线看| 亚洲第一精品在线| 久久久久国产精品人| 日韩网站在线观看| 欧美国产欧美综合| 亚洲欧洲精品天堂一级| 亚洲日本va在线观看| 麻豆精品视频在线| 性色av一区二区三区红粉影视| 在线亚洲精品福利网址导航| 亚洲乱码视频| 香蕉国产精品偷在线观看不卡 | 久久影院午夜片一区| 亚洲无吗在线| 日韩一区二区精品在线观看| 久久九九国产精品怡红院| 99精品欧美| 亚洲靠逼com| 国产精品99久久久久久有的能看| 国内精品模特av私拍在线观看| 欧美精品免费视频| 欧美日韩色一区| 国产精品婷婷| 亚洲欧美国产制服动漫| 亚洲精品1234| 国产精品久久久久av| 国产精品va| 国产精品稀缺呦系列在线| 国产伦精品一区二区三区四区免费| 欧美日韩中文精品| 欧美成年人视频| 亚洲午夜精品| 日韩亚洲精品视频| 欧美激情视频在线播放| 欧美v国产在线一区二区三区| 久久亚洲精品视频| 欧美肥婆在线| 夜夜夜久久久| 亚洲无线一线二线三线区别av| 亚洲视频一区二区| 免费短视频成人日韩| 亚洲欧美国产高清va在线播| 永久免费视频成人| 在线观看欧美激情| 欧美.www| 欧美成人免费播放| 欧美一区观看| 激情五月婷婷综合| 一本久道综合久久精品| 欧美三级精品| 亚洲欧美激情在线视频| 国产一区二区三区久久悠悠色av | 国产精品成人在线观看| 欧美精品一区二区三区一线天视频 | 亚洲欧美日韩综合| 国产精品www994| 欧美日韩ab| 欧美精品日韩www.p站| 免费成人av在线| 久久久久久精| 免费国产自线拍一欧美视频| 久久久99久久精品女同性| 久久精品123| 久久久免费精品| 亚洲伦伦在线| 欧美刺激性大交免费视频| 欧美高清在线视频| 亚洲国产专区校园欧美| 亚洲国产mv| 欧美一区二区三区免费观看视频| 亚洲小少妇裸体bbw| 久久久噜噜噜久久久| 免费人成精品欧美精品| 久久av最新网址| 欧美激情一区二区三区在线视频观看| 日韩视频在线播放| 香蕉成人伊视频在线观看| 99re66热这里只有精品3直播| 亚洲精品国产无天堂网2021| 久久久久久久尹人综合网亚洲| 欧美大片在线观看一区| 国产精品高潮呻吟久久av黑人| 激情六月婷婷综合| 一区二区三区|亚洲午夜| 欧美一区二区三区免费大片| 亚洲黄色在线| 亚洲欧美日韩在线综合| 亚洲图片欧洲图片av| 久久精品视频在线免费观看| 亚洲欧洲日韩在线| 欧美理论在线播放| 亚洲视频欧美视频| 欧美成人在线影院| 亚洲精品国产拍免费91在线| 蜜桃久久av一区| 久久久亚洲国产美女国产盗摄| 欧美丝袜一区二区| 一区二区三区高清视频在线观看| 亚洲激情视频在线播放| 另类图片国产| 亚洲精美视频| 午夜精品网站| 另类av一区二区| 亚洲一区在线视频| 在线视频欧美精品| 国产精品毛片在线看| 国产女精品视频网站免费| 小黄鸭精品aⅴ导航网站入口|