標籤:瀏覽器核心 c++ css html
在瀏覽器核心(排版引擎)CSS規則樹和HTML的DOM樹合成渲染樹的時候,會涉及到渲染樹的位置屬性的問題,因為其位置屬性將通過CSS選取器鏈的優先順序來決定,而渲染樹的某個結點可能會同時滿足多個選取器鏈,這時候就要通過選取器的優先順序來完成屬性的賦值。
在這個地方,我僅僅處理了幾個簡單的選取器情況:{(.class) (#id) (element) (#id,.class,elememt) (#id>.class) (#id element) (#id.class)}。
這時候,將渲染結點同時滿足的幾個選取器鏈通過其優先順序加權算值,從小到大依次覆蓋渲染結點;而如何確定此渲染結點是否滿足某個選取器鏈呢?
我的實現過程大致如下:
首先給定選取器的結構體如下:
struct CSSParserSelector { enum TYPE {ID,CLASS,ELEMENT}; enum RELATION {NONE,DESCENDANT,CHILD,AND}; TYPE m_Type; std::string m_Name; RELATION m_Relation; struct CSSParserSelector *ptr; CSSParserSelector():m_Relation(NONE),ptr(NULL) {}};
從本渲染結點開始,判斷此結點是否與選取器鏈表的當前選取器相匹配。如果匹配,判斷此選取器與下一個選取器的關係:如果為NONE,表示本選取器是選取器鏈的最後一個,返回成功;如果關係為AND (比如:#id.class),選擇下一個選取器與本渲染結點繼續比較;如果關係為CHILD,表示本選取器是下一個選取器的子結點,返回下一個選取器與下一個渲染結點的匹配結果;否則,關係為DESCENDANT,選取器和渲染結點各指向下一個結點,然後將渲染結點繼續回溯,直到第一個滿足回溯後的選取器的結點,此時將繼續判斷回溯後的選取器和回溯後的渲染結點是否匹配。這個過程大致如下:
/***選取器是否與渲染結點匹配*/bool RenderTree::IsSelectorsMatchRenderTree(CSSParserSelector *selector,RenderNode *renderNode){ if(IsSelectorMatchRenderNode(selector,renderNode)) { if(selector->m_Relation == CSSParserSelector::NONE) { return true; } else if(selector->m_Relation == CSSParserSelector::AND) { return IsSelectorsMatchRenderTree(selector->ptr,renderNode); } else if(selector->m_Relation == CSSParserSelector::CHILD) { return IsSelectorsMatchRenderTree(selector->ptr,renderNode->parentNode); } else { return IsMatchDescendantRelation(selector->ptr,renderNode->parentNode); } } else { return false; }}/*** 判斷與祖父關係是否匹配*/bool RenderTree::IsMatchDescendantRelation(CSSParserSelector *selector,RenderNode *renderNode){ while(renderNode->getTypeOfRenderNode() != "html" && (!IsSelectorMatchRenderNode(selector,renderNode))) { renderNode = renderNode->parentNode; } if(renderNode->getTypeOfRenderNode() != "html") { return IsSelectorsMatchRenderTree(selector,renderNode); } else { return false; }}最終便得到了匹配結果。而後通過公式便可以計算選取器鏈表的優先順序。
CSS規則樹和HTML的DOM樹合成渲染樹時渲染結點與選取器鏈的匹配