﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-My C++-随笔分类-Android-WebKit</title><link>http://www.cppblog.com/finehai/category/19061.html</link><description>当时只道是寻常~</description><language>zh-cn</language><lastBuildDate>Sat, 05 May 2012 00:47:27 GMT</lastBuildDate><pubDate>Sat, 05 May 2012 00:47:27 GMT</pubDate><ttl>60</ttl><item><title>WebKit之布局(layout)</title><link>http://www.cppblog.com/finehai/archive/2012/04/23/172479.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Mon, 23 Apr 2012 09:35:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/23/172479.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/172479.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/23/172479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/172479.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/172479.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt;"> </span><div><span style="font-size: 12pt;">WebKit 在渲染页面之前，需要确定各个元素的位置、大小，而这个过程就是layout(布局)。下面，我们对layout的主要过程进行一番说明。 </span><br /> <br /><span style="font-size: 12pt;">一、FrameView::layout方法 </span><br /><br /><span style="font-size: 12pt;">FrameView作为与View相关的类，其主要涉及与显示相关的内容，而其中对页面元素的布局至关重要，这也是浏览器的核心处理部分。 </span><br /> <br /><span style="font-size: 12pt;">我们都知道浏览器从Web服务器获得数据后，经解析会构建DOM树、Render树，然后进行布局处理，进而为渲染页面作好准备，其中的布局处理往往由FrameView::layout方法发起，让我们来具体看看其实现，一窥其主要实现过程。 </span><br /> <br /><span style="font-size: 12pt;">void FrameView::layout(bool allowSubtree) </span><br /><span style="font-size: 12pt;">{ </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (m_midLayout) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // 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. </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // 进行CSSStyleSelector的更新处理，因为一旦CSS发生变化，布局的结果也可能 发生相关变化，所以在开始布局之前，需要检查CSS是否发生变化，如果有则需要作相应调整，进而可能影响Render树等。 </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (m_frame-&gt;needsReapplyStyles()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_frame-&gt;reapplyStyles(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; else if (document-&gt;childNeedsStyleRecalc()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document-&gt;recalcStyle(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; bool subtree = m_layoutRoot; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; RenderObject* root = subtree ? m_layoutRoot : document-&gt;renderer(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (!root) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // FIXME: Do we need to set m_size here? </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_layoutSchedulingEnabled = true; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; //布局的处理可能相互嵌套，这与发起布局处理的时机相关。 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; //设置滚动条相关 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (m_canHaveScrollbars) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hMode = ScrollbarAuto; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vMode = ScrollbarAuto; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } else { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hMode = ScrollbarAlwaysOff; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vMode = ScrollbarAlwaysOff; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (!subtree) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Now set our scrollbar state for the layout. </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (body-&gt;hasTagName(framesetTag) &amp;&amp; !m_frame-&gt;settings()-&gt;frameFlatteningEnabled()) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // frameset 而且设置了frameFlatteningEnabled，则关闭滚动条 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; body-&gt;renderer()-&gt;setChildNeedsLayout(true); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vMode = ScrollbarAlwaysOff; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hMode = ScrollbarAlwaysOff; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (body-&gt;hasTagName(bodyTag)) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 设置滚动条 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; applyOverflowToViewport(o, hMode, vMode); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; //root往往为RenderView对象 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; RenderLayer* layer = root-&gt;enclosingLayer(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; m_midLayout = true; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; beginDeferredRepaints(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; root-&gt;layout(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; endDeferredRepaints(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; m_midLayout = false; </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; m_layoutSchedulingEnabled = true; </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (!subtree &amp;&amp; !static_cast(root)-&gt;printing()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adjustViewSize(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // Now update the positions of all layers. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; //对当前Render树布局完后，设置RenderLayer树的布局信息，其中m_doFullRepaint描述是否需要发起渲染处理。 </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp; beginDeferredRepaints(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp; layer-&gt;updateLayerPositions(...); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp; endDeferredRepaints(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // 设置快速blit </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; setCanBlitOnScroll(!useSlowRepaints()); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; //因为在布局的过程中，可能进一步获得网页数据，则需要继续布局处理。 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (!m_postLayoutTasksTimer.isActive()) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Calls resumeScheduledEvents() </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; performPostLayoutTasks(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!m_postLayoutTasksTimer.isActive() &amp;&amp; needsLayout()) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 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. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_postLayoutTasksTimer.startOneShot(0); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pauseScheduledEvents(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; layout(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } else { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resumeScheduledEvents(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } </span><br /><span style="font-size: 12pt;">} </span><br />  <br /> <br /><span style="font-size: 12pt;">FrameView::layout方法，简单的说来就是发起对Render树中的每一个节点按照从父节点到子节点的方式进行x、y、width、height计算，当每一个树节点的位置及大小确定之后就可以进行后面的渲染。 </span><br /> <br /><span style="font-size: 12pt;">FrameView::layout往往会调用Render树根的layout方法即RenderView::layout。 </span><br /><br /> <br /><span style="font-size: 12pt;">二、RenderView::layout方法 </span><br /> <br /><span style="font-size: 12pt;">void RenderView::layout() </span><br /><span style="font-size: 12pt;">{ </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; if (printing()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_minPrefWidth = m_maxPrefWidth = m_width; </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; bool relayoutChildren = !printing() &amp;&amp; (!m_frameView || m_width != viewWidth() || m_height != viewHeight()); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; if (relayoutChildren) { </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setChildNeedsLayout(true, false); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (RenderObject* child = firstChild(); child; child = child-&gt;nextSibling()) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (child-&gt;style()-&gt;height().isPercent() ||  child-&gt;style()-&gt;minHeight().isPercent() ||  child-&gt;style()-&gt;maxHeight().isPercent()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; child-&gt;setChildNeedsLayout(true, false); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; } </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(!m_layoutState); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; LayoutState state; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // FIXME: May be better to push a clip and avoid issuing offscreen repaints. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; state.m_clipped = false; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; m_layoutState = &amp;state; </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; if (needsLayout()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RenderBlock::layout();//类继承的好处，直接调用父类的layout </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // Reset overflow and then replace it with docWidth and docHeight. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; m_overflow.clear(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; addLayoutOverflow(IntRect(0, 0, docWidth(), docHeight())); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(m_layoutStateDisableCount == 0); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(m_layoutState == &amp;state); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; m_layoutState = 0; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; setNeedsLayout(false); </span><br /><span style="font-size: 12pt;">} </span><br /> <br /><span style="font-size: 12pt;">void RenderBlock::layout() </span><br /><span style="font-size: 12pt;">{ </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Update our first letter info now. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; updateFirstLetter(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Table cells call layoutBlock directly, so don't add any logic here. Put code into layoutBlock(). </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; layoutBlock(false); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // 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. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (hasControlClip() &amp;&amp; m_overflow) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clearLayoutOverflow(); </span><br /><span style="font-size: 12pt;">} </span><br />  <br /> <br /> <br /><span style="font-size: 12pt;">三、RenderBlock::layoutBlock方法 </span><br /> <br /><span style="font-size: 12pt;">layoutBlock 会分成两个分支：layoutInlineChildren 和 layoutBlockChildren </span><br /> <br /><span style="font-size: 12pt;">void RenderBlock::layoutBlock(bool relayoutChildren) </span><br /><span style="font-size: 12pt;">{ </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; ... </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; calcWidth();//先计算宽度 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; calcColumnWidth(); </span><br />&nbsp;&nbsp;&nbsp;  <br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; m_overflow.clear();&nbsp;&nbsp;&nbsp;  </span><br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; relayoutChildren = true; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; clearFloats(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; int previousHeight = height(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; setHeight(0); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; //这就是在布局基本概念中提到的Block-level元素的子节点要么是Block-level元素要么为Inline-level元素。 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; if (childrenInline()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; else </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; layoutBlockChildren(relayoutChildren, maxFloatBottom); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Expand our intrinsic height to encompass floats. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; if (floatBottom() &gt; (m_height - toAdd) &amp;&amp;  (isInlineBlockOrInlineTable() || isFloatingOrPositioned() ||  hasOverflowClip() || </span><br /><span style="font-size: 12pt;">(parent() &amp;&amp; parent()-&gt;isFlexibleBox() || m_hasColumns))) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; setHeight(floatBottom() + toAdd); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Now lay out our columns within this intrinsic height, since  they can slightly affect the intrinsic height as we adjust for clean  column breaks. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; int singleColumnBottom = layoutColumns(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Calculate our new height.//布局完子节点后确定父节点高度 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; int oldHeight = height(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; calcHeight(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; if (previousHeight != height()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; relayoutChildren = true; </span><br /> <br /> <br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; //另外布局属性为Fixed和absolute的元素 </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; layoutPositionedObjects(relayoutChildren || isRoot()); </span><br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if we overflow or not. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; updateScrollInfoAfterLayout(); </span><br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // Repaint with our new bounds if they are different from our old bounds. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; bool didFullRepaint = repainter.repaintAfterLayout(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; if (!didFullRepaint &amp;&amp; repaintTop != repaintBottom  &amp;&amp; (style()-&gt;visibility() == VISIBLE ||  enclosingLayer()-&gt;hasVisibleContent())) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 设置repaintRect </span><br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Make sure the rect is still non-empty after intersecting for overflow above </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!repaintRect.isEmpty()) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repaintRectangle(repaintRect); // We need to do a partial repaint of our content. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hasReflection()) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repaintRectangle(reflectedRect(repaintRect)); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; setNeedsLayout(false); </span><br /><span style="font-size: 12pt;">} </span><br /> <br />  <br /><span style="font-size: 12pt;">四、RenderBlock::layoutBlockChildren方法 </span><br /> <br /> <br /><span style="font-size: 12pt;">void RenderBlock::layoutBlockChildren(bool relayoutChildren, int&amp; maxFloatBottom) </span><br /><span style="font-size: 12pt;">{ </span><br /><span style="font-size: 12pt;">int top = borderTop() + paddingTop(); </span><br /><span style="font-size: 12pt;">int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); </span><br /> <br /> <br /> <br /> <br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // Fieldsets need to find their legend and position it inside the border of the object. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // The legend then gets skipped during normal layout. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; RenderObject* legend = layoutLegend(relayoutChildren); </span><br /> <br /> <br /> <br /><span style="font-size: 12pt;">//遍历子节点 </span><br /> <br /><span style="font-size: 12pt;">RenderBox* next = firstChildBox(); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; while (next) { </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RenderBox* child = next; </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; next = child-&gt;nextSiblingBox(); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (legend == child) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue; // Skip the legend, since it has already been positioned up in the fieldset's border. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Make sure we layout children if they need it. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // an auto value.&nbsp; Add a method to determine this, so that we can avoid the relayout. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (relayoutChildren ||  ((child-&gt;style()-&gt;height().isPercent() ||  child-&gt;style()-&gt;minHeight().isPercent() ||  child-&gt;style()-&gt;maxHeight().isPercent()) &amp;&amp;  !isRenderView())) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; child-&gt;setChildNeedsLayout(true, false); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (relayoutChildren &amp;&amp;  (child-&gt;style()-&gt;paddingLeft().isPercent() ||  child-&gt;style()-&gt;paddingRight().isPercent())) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; child-&gt;setPrefWidthsDirty(true, false); </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Handle the four types of special elements first.&nbsp; These include positioned content, floating content, compacts and </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // run-ins.&nbsp; When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (handleSpecialChild(child, marginInfo)) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue; </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Lay out the child. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom); </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; } </span><br /> <br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // Now do the handling of the bottom of the block, adding in our bottom border/padding and </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; // determining the correct collapsed bottom margin information. </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; handleBottomOfBlock(top, bottom, marginInfo); </span><br /><span style="font-size: 12pt;">} </span><br /> <br /><span style="font-size: 12pt;">layoutBlockChild 方法就比较复杂了，具体可以自己看代码。 </span><br /><br /> <br /><span style="font-size: 12pt;">五、RenderBlock::layoutInlineChildren方法 </span><br /><br /><span style="font-size: 12pt;">这个方法相当复杂，其作用就是布局文字、图像等，对文字行高确定、断行等处理，同时还包括 文字从左到右或从右到左的布局处理。具体可以参考bidi.cpp中的源码实现。 </span><br /><br /> <br /><span style="font-size: 12pt;">六、调用FrameView::layout方法的时机 </span><br /><br /><span style="font-size: 12pt;">由于从Web服务器获取的网页数据不可能一次性完成，往往需要边获取数据，边布局，然后渲染，这样才可能获得良好的用户感受。 </span><br /> <br /><span style="font-size: 12pt;">所以一旦获得主要数据如css数据及body等标签后，就可以开始布局，布局完后会根据当前条件决定是否将布局的数据渲染出来，或者继续布局处理后来获取的数据，这样也增加了布局处理过程的复杂度。 </span><br /> <br /><span style="font-size: 12pt;">而调用layout方法的时机也至关重要，因为layout本身就可能需要花费大量的时间如layoutBlockChildren、 layoutInlineChildren等处理，其往往与网页的内容有关，而网页的内容却由网页开发者来确定，对浏览器来讲是千变万化的，这就对 layout方法的实现及调用时机提出更高的要求，同时确定了其复杂性。 </span><br /> <br /><span style="font-size: 12pt;">调用layout的时机主要有获得一定DOM文档数据后调用Document::updateLayout()、需要重新使用CSS数据时调用Document::recalcStyle()、改变窗口大小后调用Frame::forceLayout()等来实现。。。 </span><br /><br /> <br /><span style="font-size: 12pt;">七、总结 </span><br /><br /><span style="font-size: 12pt;">其实WebKit涉及网页布局方面的layout方法蛮复杂的，如其他RenderObject子类也会根据自身情况重载实现layout，还有对float、fixed、absolute、inline元素等的处理，但其主要逻辑就象上面所提，这里只是汇总一下主要流程及概念，针对每一个具体标签或RenderObject的布局实现则需要更深一步的了解，希望大家能对了解WebKit的网页布局过程有一个清晰而准确的认识。。  </span><br />  </div><img src ="http://www.cppblog.com/finehai/aggbug/172479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-23 17:35 <a href="http://www.cppblog.com/finehai/archive/2012/04/23/172479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android之webkit内核JNI层与Java层 函数互相调用方法 </title><link>http://www.cppblog.com/finehai/archive/2012/04/17/171757.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Tue, 17 Apr 2012 07:58:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/17/171757.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/171757.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/17/171757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/171757.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/171757.html</trackback:ping><description><![CDATA[<div><h1><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">Java<span style="font-family: 宋体;">层调用</span><span style="font-family: Arial;">JNI</span><span style="font-family: 宋体;">层函数：</span></span></h1> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">例子</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">：</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">Java<span style="font-family: 宋体;">层</span><span style="font-family: Times New Roman;">:&nbsp;BrowserFrame::loadurl(&nbsp;)&nbsp;</span></span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span style="font-family: 宋体;">调用</span><span style="font-family: Times New Roman;">JNI</span><span style="font-family: 宋体;">别名</span><span style="font-family: Times New Roman;">:&nbsp;Nativeloadurl()&nbsp;;</span></span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">JNI&nbsp;<span style="font-family: 宋体;">层：</span></span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">WebFrame::loadurl(&nbsp;)</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">&nbsp;;</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;"></span><span style="font-family: 'Times New Roman'; font-size: 12pt; color: red;">&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; color: red;"><div>  <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; color: #ff0000; font-size: 12pt; font-weight: normal;">1、将<span style="font-family: Times New Roman;">java</span><span style="font-family: 宋体;">层中的函数对应</span><span style="font-family: Times New Roman;">JNI</span><span style="font-family: 宋体;">层中的函数，以方便调用之。</span></span></p></div></span><span style="font-family: 'Times New Roman'; font-size: 12pt; color: #000000;"><br /></span></p><p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt; color: #000000;">在JNI层定义需要用的函数</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold; color: #000000;">WebFrame::</span><span style="font-family: '宋体'; background: none repeat scroll 0% 0% #ffff00; font-size: 12pt; font-weight: bold; color: #000000;">loadurl</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold; color: #000000;">(&nbsp;)</span></p><p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold; color: red;"><br /></span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp; &nbsp; &nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt;"> static&nbsp;void&nbsp;</span><span style="font-family: 'Times New Roman'; background: none repeat scroll 0% 0% #ffff00; font-size: 12pt;">LoadUrl</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">(JNIEnv&nbsp;*env,&nbsp;jobject&nbsp;obj,&nbsp;jstring&nbsp;url)</span></p><br /> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">-----------------------------------------------------------------------------------------</span></p> <p style="margin-top: 0pt; text-indent: 0.84pt; margin-bottom: 0pt; margin-left: -0.945pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">&nbsp;&nbsp;</span><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: bold;">jniRegisterNativeMethods</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">(JNIEnv*&nbsp;env,&nbsp;const&nbsp;char*&nbsp;</span><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: bold;">className</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">,</span></p> <p style="margin-top: 0pt; text-indent: 24pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">const&nbsp;</span><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: bold;">JNINativeMethod</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">*&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">gMethods</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">,&nbsp;int&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">numMethods</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">)</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">//&nbsp;</span><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: normal;">className&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">：<span style="font-family: Times New Roman;">java</span><span style="font-family: 宋体;">层的</span></span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">类名</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">。</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">//&nbsp;gMethods&nbsp;<span style="font-family: 宋体;">：对应</span></span><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: bold;">JNINativeMethod</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">的数组。</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">------------------------------------------------------------------------------------------</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">typedef&nbsp;struct&nbsp;{&nbsp;</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;name;&nbsp;//<span style="font-family: 宋体;">函数名</span><span style="font-family: Times New Roman;">(java</span><span style="font-family: 宋体;">层中声明</span><span style="font-family: Times New Roman;">)</span></span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char*&nbsp;signature;&nbsp;//&nbsp;<span style="font-family: 宋体;">函数参数</span></span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void*&nbsp;fnPtr;&nbsp;//&nbsp;<span style="font-family: 宋体;">函数指针（指向</span><span style="font-family: Times New Roman;">JNI</span><span style="font-family: 宋体;">层&nbsp;</span><span style="font-family: Times New Roman;">-&gt;&nbsp;WebFrame::loadurl(&nbsp;)&nbsp;)</span></span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">}&nbsp;</span><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: bold;">JNINativeMethod</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">;</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">------------------------------------------------------------------------------------------</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">Eg.&nbsp;&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">将如上<span style="font-family: Times New Roman;">JNI</span><span style="font-family: 宋体;">函数使用别名：</span></span><span style="font-family: '宋体'; color: #ff9900; font-size: 12pt; font-weight: bold;">Nativeloadurl</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">(&nbsp;)</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">&nbsp;(java<span style="font-family: 宋体;">层中声明</span><span style="font-family: Times New Roman;">)</span><span style="font-family: 宋体;">，存于注册数组中。</span></span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; color: #0000ff; font-size: 12pt; font-weight: bold;">JNINativeMethod&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: bold;">gMethods[]={</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">{&nbsp;"</span><span style="font-family: '宋体'; color: #ff9900; font-size: 12pt; font-weight: bold;">nativeLoadUrl</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">",&nbsp;"(Ljava/lang/String;)V",&nbsp;(void*)&nbsp;</span><span style="font-family: '宋体'; background: none repeat scroll 0% 0% #ffff00; font-size: 12pt; font-weight: bold;">LoadUrl&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">}</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">...</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">}</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">------------------------------------------------------------------------------------------</span></p><p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;"><br /></span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal; color: #ff0000;">2.&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal; color: #ff0000;">在<span style="font-family: Times New Roman; color: #ff0000;">Java</span><span style="font-family: 宋体; color: #ff0000;">层中声明并调用函数：</span><span style="font-family: Times New Roman; color: #ff0000;">nativeLoadUrl(String&nbsp;url)</span></span></p><p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal; color: #ff0000;"><span style="font-family: Times New Roman; color: #ff0000;"><br /></span></span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">&nbsp;&nbsp;&nbsp;&nbsp;声明：</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">private&nbsp;</span><span style="font-family: '宋体'; color: #ff0000; font-size: 12pt; font-weight: normal;">native&nbsp;</span><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">void&nbsp;nativeLoadUrl(String&nbsp;url);</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">&nbsp;&nbsp;&nbsp;&nbsp;调用：</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nativeLoadUrl(url);</span></p>          <h1><span style="font-family: '宋体'; font-size: 12pt; font-weight: normal;">JNI<span style="font-family: 宋体;">层调用</span><span style="font-family: Arial;">Java</span><span style="font-family: 宋体;">函数：</span></span></h1>  <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;Download::transportUrl(WebCore::FrameView*&nbsp;view,&nbsp;WebCore::String&nbsp;url)</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;{</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebViewCore*&nbsp;viewcore&nbsp;=&nbsp;WebViewCore::getWebViewCore(view);</span></p>  <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JNIEnv*&nbsp;env&nbsp;=&nbsp;JSC::Bindings::getJNIEnv();</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jstring&nbsp;jUrl&nbsp;=&nbsp;&nbsp;env-&gt;NewString(url.characters(),&nbsp;url.length());</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">//&nbsp;</span><span style="font-family: 'Times New Roman'; color: #0000ff; font-size: 12pt; font-weight: bold;">1.&nbsp;</span><span style="font-family: 'Times New Roman'; color: #0000ff; font-size: 12pt; font-weight: bold;">获得Java该类的&nbsp;jclass对象</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jclass&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">mODP&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">=&nbsp;env-&gt;FindClass("archermind/webkit/Observor/ODP");</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">//&nbsp;</span><span style="font-family: 'Times New Roman'; color: #0000ff; font-size: 12pt; font-weight: bold;">2.&nbsp;通过该对象，取得相应java函数及参数到&nbsp;-&gt;&nbsp;jmethodID中</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmethodID&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">msendDownloadRequest&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">=&nbsp;env-&gt;GetStaticMethodID(</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt; margin-left: 36pt;"><span style="font-family: 'Times New Roman'; color: #ff9900; font-size: 12pt; font-weight: bold;">mODP</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">,&nbsp;"</span><span style="font-family: 'Times New Roman'; color: #ff9900; font-size: 12pt; font-weight: bold;">sendDownloadRequest</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "(</span><span style="font-family: 'Times New Roman'; color: #ff9900; font-size: 12pt; font-weight: bold;">Larchermind/webkit/core/WebView;Ljava/lang/Strin</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">g;)V");</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">//&nbsp;</span><span style="font-family: 'Times New Roman'; color: #0000ff; font-size: 12pt; font-weight: bold;">3.&nbsp;在JNI层中，通过函数调用CallStaticVoidMethod来调用java函数。</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;env-&gt;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">CallStaticVoidMethod</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">(mODP,&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">msendDownloadRequest</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">,&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">viewcore-&gt;getWebViewJavaObject()</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">,</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">jUrl</span><span style="font-family: 'Times New Roman'; font-size: 12pt;">);</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">//&nbsp;</span><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">viewcore-&gt;getWebViewJavaObject()&nbsp;为&nbsp;arg1&nbsp;.</span></p> <p style="margin-top: 0pt; text-indent: 36pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt; font-weight: bold;">//&nbsp;jURL&nbsp;为arg2&nbsp;.</span></p> <p style="margin-top: 0pt; margin-bottom: 0pt;"><span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;env-&gt;DeleteLocalRef(jUrl);</span></p> <span style="font-family: 'Times New Roman'; font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><br />转自：http://blog.csdn.net/weiyouyin/article/details/5739659<img src ="http://www.cppblog.com/finehai/aggbug/171757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-17 15:58 <a href="http://www.cppblog.com/finehai/archive/2012/04/17/171757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】WebKit 分析–for android</title><link>http://www.cppblog.com/finehai/archive/2012/04/11/170868.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Wed, 11 Apr 2012 02:38:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/11/170868.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/170868.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/11/170868.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/170868.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/170868.html</trackback:ping><description><![CDATA[<div><div><div id="cnblogs_post_body"><p><strong style="color: #339966; font-size: 14pt;">一、WebKit简介</strong></p><p><strong style="color: #339966; font-size: 14pt;"><br /></strong></p><p><span style="font-size: 12pt;">WebKit  是一个开源的浏览器网页排版引擎，包含WebCore排版引擎和JSCore引擎。WebCore和JSCore引擎来自于KDE项目的KHTML和  KJS开源项目。Android平台的Web引擎框架采用了WebKit项目中的WebCore和JSCore部分，上层由Java语言封装，并且作为  API提供给Android应用开发者，而底层使用WebKit核心库（WebCore和JSCore）进行网页排版。  </span></p><p><br style="color: #339966;" /><strong style="color: #339966; font-size: 14pt;">二、WebKit目录结构</strong></p><p><br /></p><p><span style="font-size: 12pt;">Android平台的WebKit模块分成Java和WebKit库两个部分，其目录结构如下表所示：</span></p> <table width="646" border="2" cellpadding="10" cellspacing="2"> <tbody> <tr> <td width="638"><strong style="font-size: 12pt;">Webkit 某块目录结构</strong></td></tr> <tr> <td valign="top" width="638"><strong style="font-size: 12pt;">Java层（根目录device\java\android\android\webkit）</strong></td></tr></tbody></table> <table width="647" border="2" cellpadding="10" cellspacing="2"> <tbody> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">BrowserFrame.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">BrowserFrame对象是对WebCore库中的Frame对象的java层封装，用于创建WebCore中定义的Frame，以及为该Frame对象提供Java层回调方法。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">ByteArrayBuilder.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">ByteArrayBuilder辅助对象，用于byte块链表的处理。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">CacheLoader.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">URL Cache载入器对象，该对象实现SteadLoader抽象基类，用于通过CacheResult对象载入内容数据。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">CacheManager.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Cache管理对象，用于java层cache对象管理。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">CacheSyncManger.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Cache同步管理对象，负责同步RAM和FLASH之间的浏览器Cache数据。实际的物理数据操作在WebSyncManager对象中完成。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">CallbackProxy.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象用于处理WebCore与UI线程消息代理类。当有Web事件产生时WebCore线程会调用该回调代理类，代理类通过消息方式通知UI线程，并且调用设置的客户对象的回调函数。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">CellList.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">CellList定义图片集合中的Cell，管理Cell图片的绘制，状态改变以及索引。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">CookieManager.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">根据RFC2109规范，管理cookies.</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">DataLoader.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">数据载入器对象，用于载入网页数据。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">DataSorter.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">尚未使用。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">DownloadListener.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">下载侦听器接口。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">DownloadManagerCore.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">下载管理器对象，管理下载列表。该对象运行于WebKit的线程中，通过CallbackProxy对象与UI线程交互。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">FileLoader.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">文件载入器，用于将文件载入到Frame中。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">FrameLoader.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Frame载入器，用于载入网页Frame数据。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">HttpAuthHandler.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Http认证处理对象，该对象会作为参数传递给BrowserCallback.displayHttpAuthDialog方法，与用户交互。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">HttpDataTime.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象是处理HTTP日期的辅助对象。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">JsConfirmResult.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Js确认请求对象。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">JsPromptResult.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Js结果提示对象，用于向用户提示Javascript运行结果。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">JsResult.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Js结果对象，用于用户交互。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">JWebCoreJavaBridge.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">用Java与WebCore库中的Timer和Cookies对象交互的桥接代码。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">LoaderListener.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">载入侦听器，用于处理载入器侦听消息。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">NetWork.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象封装网络连接逻辑，为调用者提供更高级的网络连接接口。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">PanZoom.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">用于处理图片缩放、移动等操作。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">PanZoomCellList.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">用于保存、缩放图片的Cell。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">PerfChecker.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">用于效率测试的功能对象？？？？</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">SslErrorHandler.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">用于处理SSL错误消息。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">StreamLoader.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">StreamLoader抽象类是所有内容载入器对象的基类。该类是通过消息方式控制的状态机，用于将数据载入到Frame中。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">TextDialog.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">用于处理html中文本区域叠加情况，可以使用标准的文本编辑而定义的特殊的EditText控件。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">URLUtil.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">URL处理功能函数，用于编码、解码URL字符串，以及提供附加的URL类型分析功能。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebBackForwardList.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象包含WebView对象中显示的历史数据。</span><br /></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebBackForwardListClient.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">浏览历史处理的客户接口类，所有需要接收浏览历史改变的类都需要实现该接口。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebChromeClient.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Chrome客户基类，Chrome客户对象在浏览器文档标题、进度条、图标改变时会得到通知。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebHistoryItem.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象用于保存一条网页历史数据。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebIconDataBase.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">图标数据库管理对象，所有的WebView均请求相同的图标数据库对象。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebSettings.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">WebView的管理设置数据，该对象数据是通过JNI接口从底层获取。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebSyncManager.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">数据同步对象，用于RAM数据和Flash数据的同步。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebView.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Web视图对象，用于基本的网页数据载入、显示等UI操作。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebViewClient.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">Web视图客户对象，在Web视图中有事件产生时，该对象可以获得通知。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebViewCore.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象对WebCore库进行了封装，将UI线程中的数据请求发送给WebCore处理，并且通过CallbackProxy的方式，通过消息通知UI线程数据处理结果。</span></td></tr> <tr> <td valign="top" width="221"><span style="font-size: 12pt;">WebViewDatabase.java</span></td> <td valign="top" width="416"><span style="font-size: 12pt;">该对象使用SQLiteDatabase为WebCore模块提供数据存取操作。</span></td></tr></tbody></table> <p>&nbsp;</p><p><br /></p> <p><strong style="color: #339966; font-size: 14pt;">三、WebKit模块框架</strong></p><p><strong style="color: #339966; font-size: 14pt;"><br /></strong></p> <p><span style="font-size: 12pt;">Android平台的Webkit有java层和webkit库两部分组成，java层负责与android应用层进行通信，而webkit类库负责实际的网页排版处理。Java层和C库之间通过JNI和Bridge相互调用，如下图所示：</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201123136366.png"><img title="java-webkit" style="border-width: 0px; display: inline;" alt="java-webkit" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201123145121.png" height="288" width="638" border="0" /></a> </p> <p>&nbsp;</p> <p><strong style="font-size: 12pt;">3.1 java层框架</strong></p> <p><strong style="font-size: 12pt;">3.1.1 主要类关系</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebKit模块的java层一共由41个文件组成，其中主要的类关系如下图所示：</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201132248676.png"><img title="class-relation" style="border-width: 0px; display: inline;" alt="class-relation" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201132343126.png" height="505" width="814" border="0" /></a> </p> <p>&nbsp;</p> <p><strong style="font-size: 12pt;">1. WebView</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;     WebView类是WebKit模块Java层的视图类，所有需要使用Web浏览器功能的Android都需要创建该视类对象显示和处理请求的网络资源。   目前WebKit模块支持HTTP、HTTPS、FTP以及javascript请求。WebView作为应用程序的UI接口，为用户提供一系列的网页浏  览、用户交互接口，客户程序通过这些接口访问WebKit核心代码。</span></p> <p><strong style="font-size: 12pt;">2. WebViewDatabase</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;     WebViewDatabase是WebKit模块针对SQLiteDatabase对象的封装，用于存储和获取运行时浏览器保存的缓冲数据、历史访问数  据、浏览器配置数据等。该对象是个单实例对象，通过getInstance方法获取WebViewDatabase的实例。  WebViewDatabase是WebKit模块中的内部对象，仅供WebKit框架内部使用。</span></p> <p><strong style="font-size: 12pt;">3. WebViewCore</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    WebViewCore类是java层和C层WebKit核心库的交互类，客户程序调用WebView的网页浏览相关操作会转发给  BrowserFrame对象。当WebKit核心库完成实际的数据分析和处理后会回调WebViewCore中定义的一系列JNI接口，这些接口会通过  CallbackProxy将相关事件通知相应的UI对象。</span></p> <p><strong style="font-size: 12pt;">4. CallbackProxy</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;     CallbackProxy是一个代理类，用于UI线程和WebCore线程交互。该类定义了一系列与用户相关的通知方法，当WebCore完成相应的数  据处理，则会调用CallbackProxy类中对应的方法，这些方法通过消息方式间接调用相应的处理对象的处理方法。详细的处理流程在下文中会具体分  析。</span></p> <p><strong style="font-size: 12pt;">5. BrowserFrame</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp; BrowserFrame类负责URL资源的载入、访问历史的维护、数据缓存等操作，该类通过JNI接口直接与WebKit的C库交互。</span></p> <p><strong style="font-size: 12pt;">6. JWebCoreJavaBridge</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong><span style="font-size: 12pt;">该类为java层Webkit代码提供与C层WebKit核心部分的Timer和Cookies操作相关的方法。</span></p> <p><strong style="font-size: 12pt;">7. DownloadManagerCore</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 下载管理核心类，该类负责管理网络资源下载，所有Web下载操作均由该类统一管理。该类实例运行在WebKit线程当中，与UI线程的交互是通过调用CallbackProxy对象中相应的方法完成。</span></p> <p><strong style="font-size: 12pt;">8. WebSettings</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; WEB浏览器通过该对象访问相关的用户配置信息。</span></p> <p><strong style="font-size: 12pt;">9. DownloadListener</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 下载侦听接口，如果用户代码实现该接口，则在下载开始、失败、挂起、完成等情况下，DownloadManagerCore对象会调用客户代码中实现的DownloadListener方法。</span></p> <p><strong style="font-size: 12pt;">10. WebBackForwardList</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; WebBackForwardList 对象维护用户访问历史记录，该类为客户程序提供操作访问浏览器历史数据的相关方法。</span></p> <p><strong style="font-size: 12pt;">11. WebViewClient</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; WebViewClient类定义了一系列事件方法，如果android应用程序设置了WebVieClient派生对象，则在网页载入、资源载入、页面访问错误等情况发生时，该派生对象的相应方法会被调用。</span></p> <p><strong style="font-size: 12pt;">12. WebBackForwardListClient</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; WebBackForwardListClient对象定义了对访问历史操作时可能产生的事件接口，当用户实现该接口，则在操作访问历史时（访问历史移除、访问历史 清空等）用户会得到通知。</span></p> <p><strong style="font-size: 12pt;">13. WebChromeClient</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; WebChromeClient类定义了与浏览器窗口修饰相关的事件。例如接收到Title、接收到Icon、进度变化时，WebChromeClient的相应方法会被调用。</span></p> <p>&nbsp;</p> <p><strong style="font-size: 12pt;">3.1.2 主要类的设计</strong></p> <p><strong style="font-size: 12pt;">3.1.2.1 数据载入器的设计</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    WebKit模块的java部分框架中使用数据载入器来加载相应类型的数据，目前有CacheLoader、DataLoader以及  FileLoader三类载入器，他们分别用于缓存数据、内存数据、和文件数据的载入操作。java层（WebKit模块）所有的载入器都从  StreamLoader继承（其父类为Handler），由于SteamLoader   类的基类为Handler类，因此在构建载入器时，会开启一个事件处理线程，该线程负责实际的数据载入操作，而请求线程通过消息的方式驱动数据的载入。下  图是数据载入器相关类的类图结构：</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201123289764.png"><img title="loader" style="border-width: 0px; display: inline;" alt="loader" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201123296077.png" height="426" width="500" border="0" /></a></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; StreamLoader类定义了4个不同的消息：</span></p> <blockquote> <p><span style="font-size: 12pt;">MSG_STATUS、MSG_HEADERS、MSG_DATA、MSG_END</span></p></blockquote> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    分别表示发送状态信息、发送消息头消息、发送数据消息以及数据发送完毕消息。该类提供了2个抽象保护方法以及一个公有方  法：setupStreamAndSendStatus 保护方法主要是用于构建与通信协议相关的数据流，以及向LoadListener发送状态。   buildHeaders方法是向子类提供构造特定协议消息头功能。所有载入器只有一个公有方法（load），因此当需要载入数据时，调用该方法即可。与   数据载入流程相关的类还有LoaderListener以及BrowserFrame，当数据载入事件发生时，WebKit的C库会更新载入进度，并且会   通知BrwoserFrame，BrowserFrame接收到进度条变更事件后通过CallbackProxy对象，通知View类进度条数据变更。下  买你以DataLoader类为例子，说明数据载入以及与UI交互过程（转载者注：下图看不清，等我搞清楚这个流程之后我再画一个换上。）：</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201132414102.png"><img title="dataLoader" style="border-width: 0px; display: inline;" alt="dataLoader" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201132519948.png" height="524" width="768" border="0" /></a> </p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 上图中绿色部分是BrowserFrame处理进度变更事件时，调用CallbackProxy对象通知视图变更状态的操作，在这里省略。图中灰色部分表示C层代码，而白色部分表示Java层代码。</span></p> <p>&nbsp;</p> <p><strong style="font-size: 12pt;">3.2 C层框架</strong></p> <p><strong style="font-size: 12pt;">3.2.1 C类与Java类的关系</strong></p> <p><strong style="font-size: 12pt;">1. BrowserFrame</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 与BrowserFrame Java类相对应的C++类为FrameBridge，该类对Dalvik虚拟机回调BrowserFrame类中定义的本地方法进行了封装。与BrowserFrame中回调函数（java层）相对应的C层结构定义如下：</span></p> <div id="codeSnippetWrapper"><pre id="codeSnippet" style="padding: 0px; font-size: 10pt; margin: 0em; overflow: visible; width: 87.32%; color: black; direction: ltr; border-style: none; line-height: 14pt; font-family: 'Courier New',courier,monospace; height: 342px; background-color: #f4f4f4;"><span style="color: #0000ff; font-size: 12pt;">struct</span><span style="font-size: 12pt;"> FrameBridge::JavaBrowserFrame</span><br /><span style="font-size: 12pt;">{</span><br /><span style="font-size: 12pt;">    JavaVM*   mJVM;</span><br /><span style="font-size: 12pt;">    jobject   mObj;</span><br /><span style="font-size: 12pt;">    jmethodID mStartLoadingResource;</span><br /><span style="font-size: 12pt;">    jmethodID mLoadStarted;</span><br /><span style="font-size: 12pt;">    jmethodID mUpdateHistoryForCommit;</span><br /><span style="font-size: 12pt;">    jmethodID mUpdateCurrentHistoryData;</span><br /><span style="font-size: 12pt;">    jmethodID mReportError;</span><br /><span style="font-size: 12pt;">    jmethodID setTitle;</span><br /><span style="font-size: 12pt;">    jmethodID mWindowObjectCleared;</span><br /><span style="font-size: 12pt;">    jmethodID mDidReceiveIcon;</span><br /><span style="font-size: 12pt;">    jmethodID mUpdateVisiteHistory;</span><br /><span style="font-size: 12pt;">    jmethodID mHandleUrl;</span><br /><span style="font-size: 12pt;">    jmethodID mCreateWindow;</span><br /><span style="font-size: 12pt;">    jmethodID mCloseWindow;</span><br /><span style="font-size: 12pt;">    jmethodID mDecidePolicyForFormResubmission;</span><br /><span style="font-size: 12pt;">};</span></pre><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   该结构作为FrameBridge（C   层）的一个成员变量（mJavaFrame），在FrameBridge构造函数中，用BrowserFrame（java   层）类的回调方法的偏移量初始化JavaBrowserFrame结构的各个域。初始后，当WebCore（C层）在剖析网页数据时，有Frame相关的  资源改变，比如WEB页面的主题变化，则会通过mJavaFrame结构，调用指定BrowserFrame对象的相应方法，通知Java层处理。</span></div> <div><strong style="font-size: 12pt;">2. JWebCoreJavaBridge</strong></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   与该对象相对应的C层对象为JavaBridge，javaBridge对象继承了TimerClient和CookieClient类，负责  WebCore中的定时器和Cookie管理。与Java层JWebCoreJavaBridge类中方法偏移量相关的是JavaBridge中几个成员   变量，在构造JavaBridge对象时，会初始化这些成员变量，之后有Timer或者Cookies事件产生时，WebCore会通过这些ID值，回调  对应JWebCoreJavaBridge的相应方法。</span></div> <div><strong style="font-size: 12pt;">3. LoadListener</strong></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;  与该对象相关的C层结构是 struct resourceloader_t,   该结构保存了LoadListener对象ID、CancelMethod ID以及DownloadFileMethod   ID值。当有Cancel或者Download事件产生，WebCore会回调LoadListener类中的CancelMethod或者  DownloadFileMethod。</span></div> <div><strong style="font-size: 12pt;">4. WebViewCore</strong></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;  与WebViewCore相关的C类是WebCoreViewImpl，   WebViewCoreImpl类有个JavaGlue对象作为成员变量，在构建WebCoreViewImpl对象时，用  WebViewCore（java层）中的方法ID值初始化该成员变量。并且将构建的WebCoreViewImpl对象指针赋值给  WebViewCore（java层）的mNativeClass,这样将WebViewCore（java层）和WebViewCoreImpl（C  层）关联起来。</span></div> <div><strong style="font-size: 12pt;">5. WebSettings</strong></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;  与WebSettings相关的C层结构是struct   FieldIds，该结构保存了WebSettings类中定义的属性ID以及方法ID，在WebCore初始化时（WebViewCore的静态方法中  使用System.loadLibrary载入）会设置这些方法和属性的ID值。</span></div> <div><strong style="font-size: 12pt;">6. WebView</strong></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   与WebView相关的C层类是WebViewNative，该类中的mJavaGlue中保存了WebView中定义的属性和方法ID，在  WebViewNative构造方法中初始化，并且将构造的WebViewNative对象的指针，赋值给WebView类的mNativeClass变  量，这样WebView和WebViewNative对象就建立了关系。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">3.2.2 主要类关系</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 与java层相关的C层类如下表所示：</span></div> <table width="633" border="2" cellpadding="10" cellspacing="2"> <tbody> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">ChromeClientAndroid</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该 类主要处理WebCore中与Frame装饰相关的操作。例如设置状态栏、滚动条、  Javascript脚本提示框等。当浏览器中有关事件产生时，ChromeClientAndroid类的相应方法会被调用，该类会将相关的UI事件通  过Bridge传递给Java层，由Java层负责绘制以及用户交互方面的处理。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">EditorClientAndroid</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类负责处理页面中文本相关的处理，比如文本输入、取消、输入法数据处理、文本粘贴、文本编辑等操作。不过目前该类只对按键相关的事件进行了处理，其他操作均未支持。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">ContextMenuClient</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类提供页面相关的功能菜单。比如图片拷贝、朗读、查找等功能。但是，目前项目中未实现具体功能。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">DragClient</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类定义了与页面拖拽相关的处理，但是目前该类没有实现具体功能。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">FrameLoaderClientAndroid</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类提供与Frame加载相关的操作，当用户请求加载一个页面时，WebCore分析完网页数据后，会通过该类调用Java层的回调方法，通知UI相关的组件处理。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">InspectorClientAndroid</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类提供与窗口相关的操作，比如窗口显示、关闭窗口、附加窗口等。不过目前该类的各个方法均为空实现。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">Page</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类提供与页面相关的操作，比如网页页面的前进、后退等操作。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">FrameBridge</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类对Frame相关的Java层方法进行了封装，当有Frame事件产生时，WebCore通过FrameBridge回调Java的回调函数，完成用户交互过程。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">AssetManager</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类为浏览器提供本地资源访问功能。</span></td></tr> <tr> <td valign="top" width="200"><span style="font-size: 12pt;">RenderSkinAndroid</span></td> <td valign="top" width="423"><span style="font-size: 12pt;">该类与控件绘制相关，所有的绘制控件类都需要从该类派生，目前WebKit模块中有Button、Combo、Radio三类控件。</span></td></tr></tbody></table> <p><span style="font-size: 12pt;">以上几个类会在Java层请求创建WebFrame的时候被建立，他们的关系如下图所示：</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201132535323.jpg"><img title="webFrame" style="border-width: 0px; display: inline;" alt="webFrame" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/20110420113259202.jpg" height="747" width="739" border="0" /></a> </p> <p><span style="font-size: 12pt;">上 图中标注为深绿色的FrameAndroid是浏览器Frame，一个BrowserFrame对象对应着一个FrameAndroid对象。而  其他8个标注为淡绿色的类，是与该Frame显示、布局等相关的类。WebKit模块中所有WebCore核心代码与用户交互的操作使用  FrameAndroid对象中的Briedge处理（回调相应的Java方法）。</span></p> <p>&nbsp;</p><p><br /></p> <p><strong style="color: #339966; font-size: 14pt;">四、基本操作分析</strong></p><p><strong style="color: #339966; font-size: 14pt;"><br /></strong></p> <p><strong style="font-size: 12pt;">4.1 WebKit模块初始化</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;  Android   SDK中提供了WebView类，该类为客户提供客户化浏览显示的功能，如果客户需要加入浏览器支持，可将该类的实例或者派生类的实例作为视图，调用  Activity类的SetContentView显示给用户。当客户代码中第一次生成WebView对象时，会初始化WebKit库（包括Java层和  C层两个部分），之后用户可以操作WebView对象完成网络或者本地资源的访问。</span></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   WebView对象的生成主要涉及3个类CallbackProxy、WebViewCore以及WebViewDatabase。其中  CallbackProxy对象为WebKit模块中UI线程和WebKit类库提供交互功能，WebViewCore是WebKit的核心层，负责与C   层交互以及WebKit模块C层类库初始化，而WebViewDatabase为WebKit模块运行时缓存、数据存储提供支持。WebKit模块初始化  流程如下：</span></p> <p>&nbsp;</p> <p><strong style="font-size: 12pt;">WebView</strong></p> <ul><ul><ul><li><strong style="font-size: 12pt;">+- 创建CallbackProxy对象</strong>  </li><li><strong style="font-size: 12pt;">+- 创建WebViewCore对象</strong>  <ol><ol><li>调用System.loadLibrary载入webcore类相关库（C层）  </li><li>如果是第一次初始化WebViewCore对象，创建WebCoreThread线程  </li><li>创建EventHub对象，处理WebViewCore事件  </li><li>获取WebIconDatabase对象实例  </li><li>向WebCoreThread发送初始化消息</li></ol></ol> </li><li><strong style="font-size: 12pt;">+- 获取WebViewDatabase实例</strong></li></ul></ul></ul> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    如上所述，第一步调用System.loadLIbrary方法载入webcore相关类库，该过程由Dalvik虚拟机完成，它会动态从链接库目录中寻   找libWebCore.so类库，载入内存中，并且调用WebKit初始化模块的JNI_OnLoad方法。WebKit模块的JNI_OnLoad方  法中完成如下初始化操作：</span></p> <blockquote> <p><span style="font-size: 12pt;">a) 初始化framebridge[register_android_webcore_framebridge]  </span></p><p><span style="font-size: 12pt;">初始化gFrameAndroidField静态变量，以及注册BrowserFrame类中的本地方法表。  </span></p><p><span style="font-size: 12pt;">b) 初始化javabridge[register_android_webcore_javabridge]  </span></p><p><span style="font-size: 12pt;">初始化gJavaBridge.mObject对象，以及注册JWebCoreJavaBridge类中的本地方法  </span></p><p><span style="font-size: 12pt;">c) 初始化资源loader[register_android_webcore_resource_loader]  </span></p><p><span style="font-size: 12pt;">初始化gResourceLoader静态变量，以及注册LoadListener类的本地方法  </span></p><p><span style="font-size: 12pt;">d) 初始化webviewcore[register_android_webkit_webviewcore]  </span></p><p><span style="font-size: 12pt;">初始化gWebCoreViewImplField静态变量，以及注册WebViewCore类的本地方法  </span></p><p><span style="font-size: 12pt;">e) 初始化webhistory[register_android_webkit_webhistory]  </span></p><p><span style="font-size: 12pt;">初始化gWebHistoryItem结构，以及注册WebBackForwardList和WebHistoryItem类的本地方法  </span></p><p><span style="font-size: 12pt;">f) 初始化webicondatabase[register_android_webkit_webicondatabase]  </span></p><p><span style="font-size: 12pt;">注册WebIconDatabase类的本地方法  </span></p><p><span style="font-size: 12pt;">g) 初始化websettings[register_android_webkit_websettings]  </span></p><p><span style="font-size: 12pt;">初始化gFieldIds静态变量，以及注册WebSettings类的本地方法  </span></p><p><span style="font-size: 12pt;">h) 初始化webview[register_android_webkit_webview]  </span></p><p><span style="font-size: 12pt;">初始化gWebViewNativeField静态变量，以及注册WebView类的本地方法</span></p></blockquote> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    第二步是WebCoreThread初始化，该初始化只在第一次创建WebViewCore对象时完成，当用户代码第一次生成WebView对象，会在初   始化WebViewCore类时创建WebCoreThread线程，该线程负责处理WebCore初始化事件。此时WebViewCore构造函数会被  阻塞，直到一个WebView初始化请求完毕时，会在WebCoreThread线程中唤醒。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 第三步创建EventStub对象，该对象处理WebView类的事件，当WebCore初始化完成后会向WebView对象发送事件，WebView类的EventStub对象处理该事件，并且完成后续初始化工作。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 第四步获取WebIconDatabase对象实例。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    第五步向WebViewCore发送INITIALIZE事件，并且将this指针作为消息内容传递。WebView类主要负责处理UI相关的事件，而  WebViewCore主要负责与WebCore库交互。在运行时期，UI线程和WebCore数据处理线程是运行在两个独立的线程当中。  WebCoreThread线程接收到INITIALIZE线程后，会调用消息对象参数的initialize方法，而后唤醒阻塞的  WebViewCore   Java线程（该线程在WebViewCore的构造函数中被阻塞）。不同的WebView对象实例有不同的WebViewCore对象实例，因此通过消   息的方式可以使得UI线程和WebViewCore线程解耦合。WebCoreThread的事件处理函数，处理INITIALIZE消息时，调用的是不  同WebView中WebViewCore实例的initialize方法。WebViewCore类中的initialize方法中会创建  BrowserFrame对象（该对象管理整个WEB窗体，以frame相关事件），并且向WebView对象发送  WEBCORE_INITIALIZED_MSG_ID消息。WebView消息处理函数，会根据消息参数1初始化指定的WebViewCore对象，并  且更新WebViewCore的Frame缓冲。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 初始化过程的序列图如下图所示：  </span></p><p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201133042988.png"><img title="webcore" style="border-width: 0px; display: inline;" alt="webcore" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/20110420113312277.png" height="419" width="737" border="0" /></a>  </p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 初始化完成后Java层和C层类图关系如下图所示:</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201133138716.jpg"><img title="WebView_c" style="border-width: 0px; display: inline;" alt="WebView_c" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/20110420113319597.jpg" height="685" width="737" border="0" /></a> </p> <p><span style="font-size: 12pt;">上图中淡绿色的类表示Java层，而灰色类表示C层。</span></p> <p>&nbsp;</p> <p><span style="font-size: 12pt;">4.2 数据载入</span></p> <p><strong style="font-size: 12pt;">4.2.1 载入网路数据</strong></p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    客户代码中可以使用WebView类的loadUrl方法，请求访问指定的URL网页数据。WebView对象中保存着WebViewCore的引用，由   于WebView属于UI线程，而WebViewCore属于后台线程，因此WebView对象的loadUrl被调用时，会通过消息的方式将URL信息   传递给WebViewCore对象，该对象会调用成员变量mBrowserFrame的loadUrl方法，进而调用WebKit库完成数据的载入。其调  用函数序列如下所示：</span></p> <p><a href="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/201104201133255477.png"><img title="loadurl" style="border-width: 0px; display: inline;" alt="loadurl" src="http://images.cnblogs.com/cnblogs_com/hibraincol/201104/20110420113332606.png" height="500" width="752" border="0" /></a> </p> <p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;    网络数据的载入分别由Java层和C层共同完成，Java层完成用户交互、资源下载等操作，而C层主要完成数据分析（建立DOM树、分析页面元素等）操  作。由于UI线程和WebCore线程运行在不同的两个线程中，因此当用户请求访问网络资源时，通过消息的方式向WebViewCore对象发送载入资源   请求。在Java层的WebKit模块中，所有与资源载入相关的操作都是由BrowserFrame类中对应的方法完成，这些方法是本地方法，会直接调用   WebCore库的C层函数完成数据载入请求，以及资源分析等操作。如上图所示，C层的FrameLoader类是浏览框架的资源载入器，该类负责检查访  问策略以及向Java层发送下载资源请求等功能。在FrameLoader中，当用户请求网络资源时，经过一系列的策略检查后会调用  FrameBridge的startLoadingResource方法，该方法会回调BrowserFrame（Java）类的  startLoadingResource方法，完成网络数据的下载，而后BrowserFrame（Java）类的  startLoadingResource方法会返回一个LoadListener的对象，FrameLoader会删除原有的FrameLoader对   象，将LoadListener对象封装成ResourceLoadHandler对象，并且将其设置为新的FrameLoader。到此完成了一次资源  访问请求，接下来的任务即是WebCore库会根据资源数据进行分析和构建DOM，以及相关的数据结构。</span></p> <p>&nbsp;</p> <p><strong style="font-size: 12pt;">4.2.2 载入本地数据</strong></p> <p><span style="font-size: 12pt;">本 地数据是以data://开头的URL表示，载入过程和网络数据一样，只不过在执行FrameLoader类的executeLoad方法时，会  根据URL的SCHEME类型区分，调用DataLoader的requestUrl方法（参看3.1.2.1节对载入器的分析），而不是调用  handleHTTPLoad建立实际的网络通信连接。  </span></p><p>&nbsp; </p><p><strong style="font-size: 12pt;">4.2.3 载入文件数据</strong>  </p><p><span style="font-size: 12pt;">文 件数据是以file://开头的URL，载入的基本流程与网络数据载入流程基本一致，不同的是在运行FrameLoader类的  executeLoad方法时，根据SCHEME类型，调用FileLoader的requestUrl方法，完成数据加载（参看3.1.2.1节对载入  器的分析）。  </span></p><p>&nbsp;</p> <p><strong style="font-size: 12pt;">4.3 刷新绘制</strong>  </p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   当用户拖动滚动条、有窗口遮盖、或者有页面事件触发都会向WebViewCore（Java层）对象发送背景重绘消息，该消息会引起网页数据的绘制操作。  WebKit的数据绘制可能出于效率上的考虑，没有通过Java层，而是直接在C层使用SGL库完成。与Java层图形绘制相关的Java对象有如下几  个：  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 1. Picture类  </span></p><p><span style="font-size: 12pt;">该类对SGL封装，其中变量mNativePicture实际上是保存着SkPicture对象的指针。WebViewCore中定义了两个Picture对象，当作双缓冲处理，在调用webKitDraw方法时，会交换两个缓冲区，加速刷新速度。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 2. WebView类  </span></p><p><span style="font-size: 12pt;">该 类接受用户交互相关的操作，当有滚屏、窗口遮盖、用户点击页面按钮等相关操作时，WebView对象会与之相关的WebViewCore  对象发送VIEW_SIZE_CHANGED消息。当WebViewCore对象接收到该消息后，将构建时建立的mContentPictureB刷新到  屏幕上，然后将mContentPictureA与之交换。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 3. WebViewCore类  </span></p><p><span style="font-size: 12pt;">该类封装了WebKit C层代码，为视图类提供对WebKit的操作接口，所有对WebKit库的用户请求均由该类处理，并且该类还为视图类提供了两个Picture对象，用于图形数据刷新。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 下面以Web页面被鼠标拖拽的情况为例子，分析网页数据刷新过程。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   当用户使用手指点击触摸屏，并且移动手指，则会引发touch事件的产生，Android平台会将touch事件传递给最前端的视图相应  （dispatchTouchEvent方法处理）。在WebView类中定义了5种touch模式，在手指拖动Web页面的情况下，会触发  mMotionDragMode，并且会调用View类的scrollBy方法，触发滚屏事件以及使视图无效（重绘，会调用View的onDraw方  法）。WebView视图中的滚屏事件由onScrollChanged方法响应，该方法向WebViewCore对象发送  SET_VISIBLE_RECT事件。  </span></p><p><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;   WebViewCore对象接收到SET_VISIBLE_RECT事件后，将消息参数中保存的新视图的矩形区域大小传递给  nativeSetVisibleRect方法，通知WebCoreViewImpl对象（C层）视图矩形变更  （WebCoreViewImpl::setVisibleRect方法）。在setVisibleRect方法中，会通过虚拟机调用  WebViewCore的contentInvalidate方法，该方法会引发webkitDraw方法的调用（通过WEBKIT_DRAW消息）。在  webkitDraw方法里，首先会将mContentPictureB对象传递给本地方法nativeDraw绘制，而后将  mContentPictureB的内容与mContentPictureA的内容对调。在这里mContentPictureA   缓冲区是供给WebViewCore的draw方法使用，如果用户选择某个控件，绘制焦点框时候WebViewCore对象的draw方法会调用，绘制的  内容保存在mContentPictureA中，之后会通过Canvas对象（Java层）的drawPicture方法将其绘制到屏幕上，而  mContentPictureB缓冲区是用于built操作的，nativeDraw方法中首先会将传递的mContentPictureB对象数据重   置，而后在重新构建的mContentPictureB画布上，将层上相关的元素绘制到该画布上。上面提到，之后会将mContentPictureB和   mContentPictureA的内容对调，这样一次重绘事件产生时（会调用WebView.onDraw方法）会将mContentPictureA  的数据使用Canvas类的drawPicture绘制到屏幕上。当webkitDraw方法将mContentPictureA与  mContentPictureB指针对调后，会向WebView对象发送NEW_PICTURE_MSG_ID消息，该消息会引发  WebViewCore的VIEW_SIZE_CHANGED消息的产生，并且会使当前视图无效产生重绘事件(invalidate())，引发  onDraw方法的调用，完成一次网页数据的绘制过程。  </span></p><p><span style="font-size: 12pt;">~~~ END ~~~  </span></p><p>本文转自: <a title="http://www.jjos.org/android/2010/05/10/312_webkit-webkit-for-android.html" href="http://www.jjos.org/android/2010/05/10/312_webkit-webkit-for-android.html">http://www.jjos.org/android/2010/05/10/312_webkit-webkit-for-android.html</a></p></div></div> </div><img src ="http://www.cppblog.com/finehai/aggbug/170868.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-11 10:38 <a href="http://www.cppblog.com/finehai/archive/2012/04/11/170868.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>