2010/09/28 徐彩琴的display:none改造代码评审小结

2010/09/28 徐彩琴的display:none改造代码评审小结

目录

 [隐藏] 
  • 1 背景知识
  • 2 原始目标
  • 3 具体修改点(注意:当前仅处理div的display属性改变,因GoogleMap只用到div)
    • 3.1 主要数据结构修改
    • 3.2 !none到none:WMG树上的局部detach过程
    • 3.3 !none到!none:display为list-item时的特殊处理
    • 3.4 DisplayNoneFlag对regist的控制
      • 3.4.1 DisplayNoneFlag的传播性
    • 3.5 初始为display:none的处理
  • 4 display在非none及非list-item之间的切换
  • 5 重构点(2010/09/29)

[编辑]背景知识

  1. WDT树
  2. WMG树

[编辑]原始目标

  1. 大范围:考虑CSS样式属性修改(onChangedStyleEvent)的情况下的性能改善
    1. 小范围:改善display属性改变时的性能。
      1. 原始做法:
        1. 当某div的display初始为"none"时,整个对应的WDT子树不会创建,而从none变为!none时,会导致重新create
        2. 如果是从!none(inline,block等)变为none,则整个WDT子树会被删除重建,开销较大
      2. 修改做法:
        1. 不删除WDT子树,仅仅断开对应WMG树上WDT_Parts节点之间的关联(detach过程)
        2. 在需要的时候重新调用regist(attach过程),重建WMG树,在此过程中避免了WDT_Parts节点的删除重建,因此改善了性能

[编辑]具体修改点(注意:当前仅处理div的display属性改变,因GoogleMap只用到div)

[编辑]主要数据结构修改

  1. 在每个WDT_Parts节点上增加一个DisplayNoneFlag,当为TRUE时,此节点不会挂到WMG树中

[编辑] !none到none:WMG树上的局部detach过程

  1. 根据实际的html数据,及对div设置的不同CSS样式,WDT树由上而下可能出现4类节点:clip、overflow、scroll、inline
  2. 需要从WMG树上断开的就是以一个clip节点(称‘当前节点’)为根的子树
    1. 从兄弟链上断开clip:寻找此节点的prevSibling widget,让其nextSibling指向clip的nextSibling即可
    2. 与其parent断开:调用原来的detachChild,及设置相关状态
    3. 附注:这里的parent对应于节点的Stacking Context(与CSS 2.1 描画顺序改造有关)
  3. div的display为非inline,且同时设置了width、height,此时需要断开的是2个相邻的兄弟节点:1个overflow和1个scroll
    1. 处理过程同上,我们从原始改造代码的基础上抽取出一个公共函数dettachWidgetsFromWMGTree
  4. 同上(clip情形),除了节点变成了overflow
  5. else情况(无style设置,但前面3种情况应该都可以合并到这里一种处理):inline* > ... > nextSiblingEnd
    1. WDT树中此inline节点的子女后代节点在WMG树中变成了兄弟节点,如:
      1. <div*>aaa<input>bbb</div><div'/> ==> div*(inline?) > text > input > text > div'
    2. 要断开的邻居WDT_Parts兄弟节点与第1个inline节点具有相同的LytParentWidget
      1. 根据此条件在WMG树的兄弟节点层次上往后遍历(n = n->nextSibling),直到碰到具有不同LytParentWidget的节点(如上面的div'),将前面的节点全部detach

[编辑] !none到!none:display为list-item时的特殊处理

  1. 当display取值为list-item时,inspirium原始代码将创建2个特殊的marker节点(mark和markReserve)
    1. 这2个marker节点的实际位置取决为CSS list-style-position属性的设置:
      1. list-style-position=inside:此时为widget的成员
      2. outside:此时是widget在WDT树中的头2个子女节点
    2. 目前的处理方法:只要是div,就创建2个marker节点,当display:list-item时设置到WDT树中对应位置,设置DisplayNoneFlag为FALSE,否则TRUE;然后调regist
      1. 这里需要调setLayoutSkip,它与DisplayNoneFlag配合使用
      2. 这种做法会带来内存浪费,考虑在进一步的修改中改为:必要时创建,不用时删除

[编辑]DisplayNoneFlag对regist的控制

  1. 对child.regist(parent)函数:
    1. 如果child的DisplayNoneFlag=TRUE,则跳过regist,也就是说,它不会被挂到WMG树中(当然,始终在WDT树中),也就不会参与后续的layout

[编辑]DisplayNoneFlag的传播性

  1. DisplayNoneFlag表示一节点是否实际可见。当设置某div.style.display="none"时,触发setChildWidgetDisplay过程:
    1. 其对应TAW树中所有div的子女后代节点的DisplayNoneFlag都将被设为TRUE
    2. 每个TAW Node对应的WDT Node(clip、overflow、scroll、inline)DisplayNoneFlag也都将被设为TRUE
    3. 这里需要注意CSS :before :after伪节点的处理
  2. dettach处理时,只需要设置最顶层的相关节点DisplayNoneFlag=TRUE,这样当后来重新切换为!none时,避免了递归的开销

[编辑]初始为display:none的处理

  1. 原始做法:直接return,不会创建对应的WDT子树
  2. 修改做法:创建对应的WDT子树,但其中的所有节点DisplayNoneFlag设为TRUE,这样后续regist就不会把它们挂到WMG树上

[编辑]display在非none及非list-item之间的切换

  1. 调用change过程,重设CSS样式
    1. 如果这会导致WDT树结构变化(如可能的overflow节点增加删除),则可能无法正确处理
    2. TODO:我们期望能够做到:局部地调整WDT树结构(增加删除overflow节点),然后重新regist,把WMG更新到新的一致状态

[编辑]重构点(2010/09/29)

  1. TAW Node上增加新成员currentWidget = locateBoxWrapperWidget(BOOL newDisplayNoneFlag);
    1. clip、overflow、scroll、inline的4种组合情况:
      1. parent的childrenList中:clip* -->子女节点 overflow -->m_Panel成员 --> scroll --> ...
      2. parent的childrenList中:overflow* -->m_Panel成员 --> scroll --> ...
      3. parent的childrenList中:overflow*(m_Panel为NULL,无scroll) --> ...
      4. parent的childrenList中:直接为inline*
    2. 由于scroll存在的情况下必定是overflow的成员,不是单独的Widget节点,因此locateBoxWrapperWidget永远不会返回scroll
  2. detach过程统一处理:currentWidget->dettachFromWMGTree();

你可能感兴趣的:(历史记录)