参考地址:http://blog.csdn.net/dlmu2001/article/details/6164873

1.    描述

Frame类是WebCore内核同应用之间联系的一个重要的类。它有点像设计模式中的Façade,将内核的各个不同的零配件组装在了一起,但又不是Façade,因为用户很多时候还是要直接去操作里面的组件。除了设计上的考虑,Frame还有语法上的意义,它对应于Page里面的帧。

看一下类定义:

  class Frame : public RefCounted<Frame>, public TiledBackingStoreClient {
public:
static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); void init();
void setView(PassRefPtr<FrameView>);
void createView(const IntSize&, const Color&, bool, const IntSize&, bool,
ScrollbarMode = ScrollbarAuto, bool horizontalLock = false,
ScrollbarMode = ScrollbarAuto, bool verticalLock = false); ~Frame(); void addDestructionObserver(FrameDestructionObserver*);
void removeDestructionObserver(FrameDestructionObserver*); void detachFromPage();
void pageDestroyed();
void disconnectOwnerElement(); Page* page() const;
HTMLFrameOwnerElement* ownerElement() const; Document* document() const;
FrameView* view() const; Editor* editor() const;
EventHandler* eventHandler() const;
FrameLoader* loader() const;
NavigationScheduler* navigationScheduler() const;
SelectionController* selection() const;
FrameTree* tree() const;
AnimationController* animation() const;
ScriptController* script(); RenderView* contentRenderer() const; // Root of the render tree for the document contained in this frame.
RenderPart* ownerRenderer() const; // Renderer for the element that contains this frame. void transferChildFrameToNewDocument(); // ======== All public functions below this point are candidates to move out of Frame into another class. ======== bool isDisconnected() const;
void setIsDisconnected(bool);
bool excludeFromTextSearch() const;
void setExcludeFromTextSearch(bool); void injectUserScripts(UserScriptInjectionTime); String layerTreeAsText(bool showDebugInfo = false) const; // Unlike most accessors in this class, domWindow() always creates a new DOMWindow if m_domWindow is null.
// Callers that don't need a new DOMWindow to be created should use existingDOMWindow().
DOMWindow* domWindow() const;
DOMWindow* existingDOMWindow() { return m_domWindow.get(); }
void setDOMWindow(DOMWindow*);
void clearFormerDOMWindow(DOMWindow*);
void clearDOMWindow(); static Frame* frameForWidget(const Widget*); Settings* settings() const; // can be NULL enum AdjustViewSizeOrNot { DoNotAdjustViewSize, AdjustViewSize };
void setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot); bool inViewSourceMode() const;
void setInViewSourceMode(bool = true); void keepAlive(); // Used to keep the frame alive when running a script that might destroy it.
static void cancelAllKeepAlive(); void setDocument(PassRefPtr<Document>); void setPageZoomFactor(float factor);
float pageZoomFactor() const { return m_pageZoomFactor; }
void setTextZoomFactor(float factor);
float textZoomFactor() const { return m_textZoomFactor; }
void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor); void scalePage(float scale, const IntPoint& origin);
float pageScaleFactor() const { return m_pageScaleFactor; } #if ENABLE(ORIENTATION_EVENTS)
// Orientation is the interface orientation in degrees. Some examples are:
// 0 is straight up; -90 is when the device is rotated 90 clockwise;
// 90 is when rotated counter clockwise.
void sendOrientationChangeEvent(int orientation);
int orientation() const { return m_orientation; }
#endif void clearTimers();
static void clearTimers(FrameView*, Document*); String documentTypeString() const; String displayStringModifiedByEncoding(const String&) const; DragImageRef nodeImage(Node*);
DragImageRef dragImageForSelection(); VisiblePosition visiblePositionForPoint(const IntPoint& framePoint);
Document* documentAtPoint(const IntPoint& windowPoint);
PassRefPtr<Range> rangeForPoint(const IntPoint& framePoint); String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*, size_t* resultDistanceFromStartOfCell);
String searchForLabelsBeforeElement(const Vector<String>& labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);
String matchLabelsAgainstElement(const Vector<String>& labels, Element*); Color getDocumentBackgroundColor() const; #if PLATFORM(MAC)
NSString* searchForLabelsBeforeElement(NSArray* labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);
NSString* matchLabelsAgainstElement(NSArray* labels, Element*); NSImage* selectionImage(bool forceBlackText = false) const;
NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const;
NSImage* imageFromRect(NSRect) const;
#endif #if ENABLE(MEDIA_STREAM)
MediaStreamFrameController* mediaStreamFrameController() const { return m_mediaStreamFrameController.get(); }
#endif // ======== private:
Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); void injectUserScriptsForWorld(DOMWrapperWorld*, const UserScriptVector&, UserScriptInjectionTime);
void lifeSupportTimerFired(Timer<Frame>*); #if USE(ACCELERATED_COMPOSITING)
void updateContentsScale(float);
#endif HashSet<FrameDestructionObserver*> m_destructionObservers; 138 Page* m_page;
139 mutable FrameTree m_treeNode;
140 mutable FrameLoader m_loader;
141 mutable NavigationScheduler m_navigationScheduler;
142
143 mutable RefPtr<DOMWindow> m_domWindow;
144 HashSet<DOMWindow*> m_liveFormerWindows;
145
146 HTMLFrameOwnerElement* m_ownerElement;
147 RefPtr<FrameView> m_view;
148 RefPtr<Document> m_doc;
149
150 ScriptController m_script;
151
152 mutable Editor m_editor;
153 mutable SelectionController m_selectionController;
154 mutable EventHandler m_eventHandler;
155 mutable AnimationController m_animationController;
156
157 Timer<Frame> m_lifeSupportTimer;
158
159 float m_pageZoomFactor;
160 float m_textZoomFactor;
161
162 float m_pageScaleFactor;
163
164 #if ENABLE(ORIENTATION_EVENTS)
165 int m_orientation;
166 #endif
167
168 bool m_inViewSourceMode;
169 bool m_isDisconnected;
170 bool m_excludeFromTextSearch; #if ENABLE(TILED_BACKING_STORE)
// FIXME: The tiled backing store belongs in FrameView, not Frame. public:
TiledBackingStore* tiledBackingStore() const { return m_tiledBackingStore.get(); }
void setTiledBackingStoreEnabled(bool); private:
// TiledBackingStoreClient interface
virtual void tiledBackingStorePaintBegin();
virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&);
virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea);
virtual IntRect tiledBackingStoreContentsRect();
virtual IntRect tiledBackingStoreVisibleRect();
virtual Color tiledBackingStoreBackgroundColor() const; OwnPtr<TiledBackingStore> m_tiledBackingStore;
#endif #if ENABLE(MEDIA_STREAM)
OwnPtr<MediaStreamFrameController> m_mediaStreamFrameController;
#endif
}

2.    类结构

1,FrameTree对象用来协助管理父帧和子帧的关系,常见的比如 main frame之中有 iframe元素,就会调用 FrameLoaderClientQt::createFrame来产生子帧,产生的子帧会通过appendChild添加到主帧的树状结构中。Frame通过FrameTree对象,可以方便的访问它的父帧,子帧,兄弟帧。

 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
{
bool allowsScrolling = true;
int marginWidth = -;
int marginHeight = -;
if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
marginWidth = o->marginWidth();
marginHeight = o->marginHeight();
} if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
FrameLoader::reportLocalLoadFailed(m_frame, url.string());
return ;
} if (!ownerElement->document()->contentSecurityPolicy()->allowChildFrameFromSource(url))
return ; bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight); if (!frame) {
m_frame->loader()->checkCallImplicitClose();
return ;
} // All new frames will have m_isComplete set to true at this point due to synchronously loading
// an empty document in FrameLoader::init(). But many frames will now be starting an
// asynchronous load of url, so we set m_isComplete to false and then check if the load is
// actually completed below. (Note that we set m_isComplete to false even for synchronous
// loads, so that checkCompleted() below won't bail early.)
// FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
frame->loader()->started(); RenderObject* renderer = ownerElement->renderer();
FrameView* view = frame->view();
if (renderer && renderer->isWidget() && view)
toRenderWidget(renderer)->setWidget(view); m_frame->loader()->checkCallImplicitClose(); // Some loads are performed synchronously (e.g., about:blank and loads
// cancelled by returning a null ResourceRequest from requestFromDelegate).
// In these cases, the synchronous load would have finished
// before we could connect the signals, so make sure to send the
// completed() signal for the child by hand and mark the load as being
// complete.
// FIXME: In this case the Frame will have finished loading before
// it's being added to the child list. It would be a good idea to
// create the child first, then invoke the loader separately.
if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
frame->loader()->checkCompleted(); return frame.get();
}

然后就是创建看createFrame函数

 PassRefPtr<Frame> FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
{
if (!m_webFrame)
return ; QWebFrameData frameData(m_frame->page(), m_frame, ownerElement, name); if (url.isEmpty())
frameData.url = blankURL();
else
frameData.url = url; frameData.referrer = referrer;
frameData.allowsScrolling = allowsScrolling;
frameData.marginWidth = marginWidth;
frameData.marginHeight = marginHeight; QPointer<QWebFrame> webFrame = new QWebFrame(m_webFrame, &frameData);
// The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
if (!webFrame->d->frame->page()) {
frameData.frame.release();
ASSERT(webFrame.isNull());
return ;
} emit m_webFrame->page()->frameCreated(webFrame); // FIXME: Set override encoding if we have one. m_frame->loader()->loadURLIntoChildFrame(frameData.url, frameData.referrer, frameData.frame.get()); // The frame's onload handler may have removed it from the document.
if (!frameData.frame->tree()->parent())
return ; return frameData.frame.release();
}
 void FrameTree::appendChild(PassRefPtr<Frame> child)
{
ASSERT(child->page() == m_thisFrame->page());
child->tree()->m_parent = m_thisFrame;
actuallyAppendChild(child); // Note, on return |child| is null.
}

2,维护FrameLoader对象用来完成frame的加载,FrameLoader是一个非常重要的类,后续进行进一步的分析。

3,维护NavigationScheduler对象用来管理页面跳转调度(比如重定向,meta refresh等)。

4,DOMWindow用来管理同 DOM 相关的事件、属性和消息。

5,FrameView类用于Frame的排版

6,Frame文档解析后,对于每一个tag或者attr,会有对应的dom节点关联,Document类用来管理这些dom节点。不同的文档类型继承出不同的子类,比如HTML文档对应子类 HTMLDocument,XML文档对应于XMLDocument。

7,ScriptController对象。脚本控制器,用来管理脚本的执行和操作

8,Editor对象用来处理页面的编辑相关工作,比如拷贝,粘贴,输入等,Editor对象,它同Page类的 EditorClient对象紧密合作。 和EditorClient关系就如同 Page和 Frame的关系

9,SelectionController 用来管理 Frame中的选取操作

10,AnimationController 动画控制,控制动画的播放、暂停、继续(同 HTML video标签是否有关系?)

11,EventHandler 事件处理对象,这里的对象主要是同上层应用也即是用户参与的事件, 比如鼠标事件、按键事件(快捷键等)、滚动事件、resize事件等。这是一个浏览器外壳经常需要打交道的类

3.    主要接口

3.1   Create

 static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);

 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
{
RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
if (!ownerElement)
page->setMainFrame(frame);
return frame.release();
}

描述:
      调用Frame构造函数,创建出 Frame 对象。 有两个地方会创建 Frame对象: 一个是要加载一个新的页面请求,这时候会创建一个 main frame。 一个是 在加载子帧的时候,通过 FrameLoaderClientQt 的

createFrame接口,创建子帧对应的Frame对象,在第一种情况下 HTMLFrameOwnerElement的参数为NULL, 第二种情况传子帧的父元素。在一个tab页内,main frame会重用

调用系列:

 QwebPage::setView
QwebPage::setViewportSize
QwebPage::mainFrame
QwebPagePrivate::createMainFrame
QwebFrameData::QwebFrameData
Frame::create FrameLoader::finishedLoading
......
HTMLDocumentParser::append
......
HTMLTreeBuilder::processToken
......
HTMLElementBase::openURL
SubFrameLoader::requestFrame
......
FrameLoaderClientQt::creatFrame
QwebFrameData::QwebFrameData
Frame::create

源码追踪一下(只跟踪源码和颜色标识,不解释):

第一种情况下:

1,

 void QWebPage::setView(QWidget* view)
{
if (this->view() == view)
return; d->view = view;
7 setViewportSize(view ? view->size() : QSize(0, 0)); // If we have no client, we install a special client delegating
// the responsibility to the QWidget. This is the code path
// handling a.o. the "legacy" QWebView.
//
// If such a special delegate already exist, we substitute the view. if (d->client) {
if (d->client->isQWidgetClient())
static_cast<PageClientQWidget*>(d->client.get())->view = view;
return;
} if (view)
d->client = new PageClientQWidget(view, this);
}

2,

 void QWebPage::setViewportSize(const QSize &size) const
{
d->viewportSize = size; QWebFrame *frame = mainFrame();
if (frame->d->frame && frame->d->frame->view()) {
WebCore::FrameView* view = frame->d->frame->view();
view->resize(size);
view->adjustViewSize();
}
}

3,

 QWebFrame *QWebPage::mainFrame() const
{
d->createMainFrame();
return d->mainFrame;
}

4,

 void QWebPagePrivate::createMainFrame()
{
if (!mainFrame) {
QWebFrameData frameData(page);
mainFrame = new QWebFrame(q, &frameData); emit q->frameCreated(mainFrame);
}
}

5,

     QWebFrameData(WebCore::Page*, WebCore::Frame* parentFrame = ,
WebCore::HTMLFrameOwnerElement* = 0,
const WTF::String& frameName = WTF::String());

6,

 QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame,
WebCore::HTMLFrameOwnerElement* ownerFrameElement,
const WTF::String& frameName)
: name(frameName)
, ownerElement(ownerFrameElement)
, page(parentPage)
, allowsScrolling(true)
, marginWidth()
, marginHeight()
{
frameLoaderClient = new FrameLoaderClientQt();
frame = Frame::create(page, ownerElement, frameLoaderClient); // FIXME: All of the below should probably be moved over into WebCore
frame->tree()->setName(name);
if (parentFrame)
parentFrame->tree()->appendChild(frame);
}

第二种情况下:

1,FrameLoader::finishedLoading()

 void FrameLoader::finishedLoading()
{
// Retain because the stop may release the last reference to it.
RefPtr<Frame> protect(m_frame); RefPtr<DocumentLoader> dl = activeDocumentLoader();
dl->finishedLoading();
if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
return;
dl->setPrimaryLoadComplete(true);
m_client->dispatchDidLoadMainResource(dl.get());
checkLoadComplete();
}

2,DocumentLoader::finishedLoading()

 void DocumentLoader::finishedLoading()
{
m_gotFirstByte = true;
commitIfReady();
if (FrameLoader* loader = frameLoader()) {
loader->finishedLoadingDocument(this);
m_writer.end();
}
}

3,DocumentWriter::end()

 void DocumentWriter::end()
{
m_frame->loader()->didEndDocument();
endIfNotLoadingMainResource();
}

4, DocumentWriter::endIfNotLoadingMainResource()

 void DocumentWriter::endIfNotLoadingMainResource()
{
if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
return; // http://bugs.webkit.org/show_bug.cgi?id=10854
// The frame's last ref may be removed and it can be deleted by checkCompleted(),
// so we'll add a protective refcount
RefPtr<Frame> protector(m_frame); // make sure nothing's left in there
addData(0, 0, true);
m_frame->document()->finishParsing();
}

5,DocumentWriter::addData(const char* str, int len, bool flush)

 void DocumentWriter::addData(const char* str, int len, bool flush)
{
if (len == -)
len = strlen(str); DocumentParser* parser = m_frame->document()->parser();
if (parser)
parser->appendBytes(this, str, len, flush);
}

6,DecodedDataDocumentParser::appendBytes(DocumentWriter* writer , const char* data, int length, bool shouldFlush)

 void DecodedDataDocumentParser::appendBytes(DocumentWriter* writer , const char* data, int length, bool shouldFlush)
{
if (!length && !shouldFlush)
return; TextResourceDecoder* decoder = writer->createDecoderIfNeeded();
String decoded = decoder->decode(data, length);
if (shouldFlush)
decoded += decoder->flush();
if (decoded.isEmpty())
return; writer->reportDataReceived(); append(decoded);
}

7,HTMLDocumentParser::append(const SegmentedString& source)

 void HTMLDocumentParser::append(const SegmentedString& source)
{
if (isStopped())
return; // pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
RefPtr<HTMLDocumentParser> protect(this); if (m_preloadScanner) {
if (m_input.current().isEmpty() && !isWaitingForScripts()) {
// We have parsed until the end of the current input and so are now moving ahead of the preload scanner.
// Clear the scanner so we know to scan starting from the current input point if we block again.
m_preloadScanner.clear();
} else {
m_preloadScanner->appendToEnd(source);
if (isWaitingForScripts())
m_preloadScanner->scan();
}
} m_input.appendToEnd(source); if (inPumpSession()) {
// We've gotten data off the network in a nested write.
// We don't want to consume any more of the input stream now. Do
// not worry. We'll consume this data in a less-nested write().
return;
} pumpTokenizerIfPossible(AllowYield); endIfDelayed();
}

8,HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)

 void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
{
if (isStopped() || m_treeBuilder->isPaused())
return; // Once a resume is scheduled, HTMLParserScheduler controls when we next pump.
if (isScheduledForResume()) {
ASSERT(mode == AllowYield);
return;
} pumpTokenizer(mode);
}

9,HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)

 void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
{
ASSERT(!isStopped());
ASSERT(!isScheduledForResume());
// ASSERT that this object is both attached to the Document and protected.
ASSERT(refCount() >= ); PumpSession session(m_pumpSessionNestingLevel); // We tell the InspectorInstrumentation about every pump, even if we
// end up pumping nothing. It can filter out empty pumps itself.
// FIXME: m_input.current().length() is only accurate if we
// end up parsing the whole buffer in this pump. We should pass how
// much we parsed as part of didWriteHTML instead of willWriteHTML.
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().length(), m_tokenizer->lineNumber()); while (canTakeNextToken(mode, session) && !session.needsYield) {
if (!isParsingFragment())
m_sourceTracker.start(m_input, m_token); if (!m_tokenizer->nextToken(m_input.current(), m_token))
break; if (!isParsingFragment()) {
m_sourceTracker.end(m_input, m_token); // We do not XSS filter innerHTML, which means we (intentionally) fail
// http/tests/security/xssAuditor/dom-write-innerHTML.html
m_xssFilter.filterToken(m_token);
} m_treeBuilder->constructTreeFromToken(m_token);
ASSERT(m_token.isUninitialized());
} // Ensure we haven't been totally deref'ed after pumping. Any caller of this
// function should be holding a RefPtr to this to ensure we weren't deleted.
ASSERT(refCount() >= ); if (isStopped())
return; if (session.needsYield)
m_parserScheduler->scheduleForResume(); if (isWaitingForScripts()) {
ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
if (!m_preloadScanner) {
m_preloadScanner = adoptPtr(new HTMLPreloadScanner(document()));
m_preloadScanner->appendToEnd(m_input.current());
}
m_preloadScanner->scan();
} InspectorInstrumentation::didWriteHTML(cookie, m_tokenizer->lineNumber());
}

10,HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken)

 void HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken)
{
AtomicHTMLToken token(rawToken); // We clear the rawToken in case constructTreeFromAtomicToken
// synchronously re-enters the parser. We don't clear the token immedately
// for Character tokens because the AtomicHTMLToken avoids copying the
// characters by keeping a pointer to the underlying buffer in the
// HTMLToken. Fortuantely, Character tokens can't cause use to re-enter
// the parser.
//
// FIXME: Top clearing the rawToken once we start running the parser off
// the main thread or once we stop allowing synchronous JavaScript
// execution from parseMappedAttribute.
if (rawToken.type() != HTMLToken::Character)
rawToken.clear(); constructTreeFromAtomicToken(token); if (!rawToken.isUninitialized()) {
ASSERT(rawToken.type() == HTMLToken::Character);
rawToken.clear();
}
}

11,HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token)

 void HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token)
{
processToken(token); // Swallowing U+0000 characters isn't in the HTML5 spec, but turning all
// the U+0000 characters into replacement characters has compatibility
// problems.
m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || m_insertionMode == InForeignContentMode);
m_parser->tokenizer()->setShouldAllowCDATA(m_insertionMode == InForeignContentMode && !isInHTMLNamespace(m_tree.currentNode()));
}

12,HTMLTreeBuilder::processToken(AtomicHTMLToken& token)

 void HTMLTreeBuilder::processToken(AtomicHTMLToken& token)
{
switch (token.type()) {
case HTMLToken::Uninitialized:
ASSERT_NOT_REACHED();
break;
case HTMLToken::DOCTYPE:
processDoctypeToken(token);
break;
case HTMLToken::StartTag:
processStartTag(token);
break;
case HTMLToken::EndTag:
processEndTag(token);
break;
case HTMLToken::Comment:
processComment(token);
return;
case HTMLToken::Character:
processCharacter(token);
break;
case HTMLToken::EndOfFile:
processEndOfFile(token);
break;
}
}

13,HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)

 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
{
ASSERT(token.type() == HTMLToken::StartTag);
switch (insertionMode()) {
case InitialMode:
ASSERT(insertionMode() == InitialMode);
defaultForInitial();
// Fall through.
case BeforeHTMLMode:
ASSERT(insertionMode() == BeforeHTMLMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagBeforeHTML(token);
setInsertionMode(BeforeHeadMode);
return;
}
defaultForBeforeHTML();
// Fall through.
case BeforeHeadMode:
ASSERT(insertionMode() == BeforeHeadMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == headTag) {
m_tree.insertHTMLHeadElement(token);
setInsertionMode(InHeadMode);
return;
}
defaultForBeforeHead();
// Fall through.
case InHeadMode:
ASSERT(insertionMode() == InHeadMode);
if (processStartTagForInHead(token))
return;
defaultForInHead();
// Fall through.
case AfterHeadMode:
ASSERT(insertionMode() == AfterHeadMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == bodyTag) {
m_framesetOk = false;
m_tree.insertHTMLBodyElement(token);
setInsertionMode(InBodyMode);
return;
}
if (token.name() == framesetTag) {
m_tree.insertHTMLElement(token);
setInsertionMode(InFramesetMode);
return;
}
if (token.name() == baseTag
|| token.name() == basefontTag
|| token.name() == bgsoundTag
|| token.name() == linkTag
|| token.name() == metaTag
|| token.name() == noframesTag
|| token.name() == scriptTag
|| token.name() == styleTag
|| token.name() == titleTag) {
parseError(token);
ASSERT(m_tree.head());
m_tree.openElements()->pushHTMLHeadElement(m_tree.head());
processStartTagForInHead(token);
m_tree.openElements()->removeHTMLHeadElement(m_tree.head());
return;
}
if (token.name() == headTag) {
parseError(token);
return;
}
defaultForAfterHead();
// Fall through
case InBodyMode:
ASSERT(insertionMode() == InBodyMode);
processStartTagForInBody(token);
break;
case InTableMode:
ASSERT(insertionMode() == InTableMode);
processStartTagForInTable(token);
break;
case InCaptionMode:
ASSERT(insertionMode() == InCaptionMode);
if (isCaptionColOrColgroupTag(token.name())
|| isTableBodyContextTag(token.name())
|| isTableCellContextTag(token.name())
|| token.name() == trTag) {
parseError(token);
if (!processCaptionEndTagForInCaption()) {
ASSERT(isParsingFragment());
return;
}
reprocessStartTag(token);
return;
}
processStartTagForInBody(token);
break;
case InColumnGroupMode:
ASSERT(insertionMode() == InColumnGroupMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == colTag) {
m_tree.insertSelfClosingHTMLElement(token);
return;
}
if (!processColgroupEndTagForInColumnGroup()) {
ASSERT(isParsingFragment());
return;
}
reprocessStartTag(token);
break;
case InTableBodyMode:
ASSERT(insertionMode() == InTableBodyMode);
if (token.name() == trTag) {
m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop?
m_tree.insertHTMLElement(token);
setInsertionMode(InRowMode);
return;
}
if (isTableCellContextTag(token.name())) {
parseError(token);
processFakeStartTag(trTag);
ASSERT(insertionMode() == InRowMode);
reprocessStartTag(token);
return;
}
if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) {
// FIXME: This is slow.
if (!m_tree.openElements()->inTableScope(tbodyTag.localName()) && !m_tree.openElements()->inTableScope(theadTag.localName()) && !m_tree.openElements()->inTableScope(tfootTag.localName())) {
ASSERT(isParsingFragment());
parseError(token);
return;
}
m_tree.openElements()->popUntilTableBodyScopeMarker();
ASSERT(isTableBodyContextTag(m_tree.currentElement()->localName()));
processFakeEndTag(m_tree.currentElement()->tagQName());
reprocessStartTag(token);
return;
}
processStartTagForInTable(token);
break;
case InRowMode:
ASSERT(insertionMode() == InRowMode);
if (isTableCellContextTag(token.name())) {
m_tree.openElements()->popUntilTableRowScopeMarker();
m_tree.insertHTMLElement(token);
setInsertionMode(InCellMode);
m_tree.activeFormattingElements()->appendMarker();
return;
}
if (token.name() == trTag
|| isCaptionColOrColgroupTag(token.name())
|| isTableBodyContextTag(token.name())) {
if (!processTrEndTagForInRow()) {
ASSERT(isParsingFragment());
return;
}
ASSERT(insertionMode() == InTableBodyMode);
reprocessStartTag(token);
return;
}
processStartTagForInTable(token);
break;
case InCellMode:
ASSERT(insertionMode() == InCellMode);
if (isCaptionColOrColgroupTag(token.name())
|| isTableCellContextTag(token.name())
|| token.name() == trTag
|| isTableBodyContextTag(token.name())) {
// FIXME: This could be more efficient.
if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) {
ASSERT(isParsingFragment());
parseError(token);
return;
}
closeTheCell();
reprocessStartTag(token);
return;
}
processStartTagForInBody(token);
break;
case AfterBodyMode:
case AfterAfterBodyMode:
ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
setInsertionMode(InBodyMode);
reprocessStartTag(token);
break;
case InHeadNoscriptMode:
ASSERT(insertionMode() == InHeadNoscriptMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == basefontTag
|| token.name() == bgsoundTag
|| token.name() == linkTag
|| token.name() == metaTag
|| token.name() == noframesTag
|| token.name() == styleTag) {
bool didProcess = processStartTagForInHead(token);
ASSERT_UNUSED(didProcess, didProcess);
return;
}
if (token.name() == htmlTag || token.name() == noscriptTag) {
parseError(token);
return;
}
defaultForInHeadNoscript();
processToken(token);
break;
case InFramesetMode:
ASSERT(insertionMode() == InFramesetMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == framesetTag) {
m_tree.insertHTMLElement(token);
return;
}
if (token.name() == frameTag) {
m_tree.insertSelfClosingHTMLElement(token);
return;
}
if (token.name() == noframesTag) {
processStartTagForInHead(token);
return;
}
parseError(token);
break;
case AfterFramesetMode:
case AfterAfterFramesetMode:
ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == noframesTag) {
processStartTagForInHead(token);
return;
}
parseError(token);
break;
case InSelectInTableMode:
ASSERT(insertionMode() == InSelectInTableMode);
if (token.name() == captionTag
|| token.name() == tableTag
|| isTableBodyContextTag(token.name())
|| token.name() == trTag
|| isTableCellContextTag(token.name())) {
parseError(token);
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
processEndTag(endSelect);
reprocessStartTag(token);
return;
}
// Fall through
case InSelectMode:
ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
if (token.name() == htmlTag) {
m_tree.insertHTMLHtmlStartTagInBody(token);
return;
}
if (token.name() == optionTag) {
if (m_tree.currentNode()->hasTagName(optionTag)) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
processEndTag(endOption);
}
m_tree.insertHTMLElement(token);
return;
}
if (token.name() == optgroupTag) {
if (m_tree.currentNode()->hasTagName(optionTag)) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
processEndTag(endOption);
}
if (m_tree.currentNode()->hasTagName(optgroupTag)) {
AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
processEndTag(endOptgroup);
}
m_tree.insertHTMLElement(token);
return;
}
if (token.name() == selectTag) {
parseError(token);
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
processEndTag(endSelect);
return;
}
if (token.name() == inputTag
|| token.name() == keygenTag
|| token.name() == textareaTag) {
parseError(token);
if (!m_tree.openElements()->inSelectScope(selectTag)) {
ASSERT(isParsingFragment());
return;
}
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
processEndTag(endSelect);
reprocessStartTag(token);
return;
}
if (token.name() == scriptTag) {
bool didProcess = processStartTagForInHead(token);
ASSERT_UNUSED(didProcess, didProcess);
return;
}
break;
case InTableTextMode:
defaultForInTableText();
processStartTag(token);
break;
case InForeignContentMode: {
if (shouldProcessForeignContentUsingInBodyInsertionMode(token, m_tree.currentNode())) {
processForeignContentUsingInBodyModeAndResetMode(token);
return;
}
if (token.name() == bTag
|| token.name() == bigTag
|| token.name() == blockquoteTag
|| token.name() == bodyTag
|| token.name() == brTag
|| token.name() == centerTag
|| token.name() == codeTag
|| token.name() == ddTag
|| token.name() == divTag
|| token.name() == dlTag
|| token.name() == dtTag
|| token.name() == emTag
|| token.name() == embedTag
|| isNumberedHeaderTag(token.name())
|| token.name() == headTag
|| token.name() == hrTag
|| token.name() == iTag
|| token.name() == imgTag
|| token.name() == liTag
|| token.name() == listingTag
|| token.name() == menuTag
|| token.name() == metaTag
|| token.name() == nobrTag
|| token.name() == olTag
|| token.name() == pTag
|| token.name() == preTag
|| token.name() == rubyTag
|| token.name() == sTag
|| token.name() == smallTag
|| token.name() == spanTag
|| token.name() == strongTag
|| token.name() == strikeTag
|| token.name() == subTag
|| token.name() == supTag
|| token.name() == tableTag
|| token.name() == ttTag
|| token.name() == uTag
|| token.name() == ulTag
|| token.name() == varTag
|| (token.name() == fontTag && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr)))) {
parseError(token);
m_tree.openElements()->popUntilForeignContentScopeMarker();
resetInsertionModeAppropriately();
reprocessStartTag(token);
return;
}
const AtomicString& currentNamespace = m_tree.currentElement()->namespaceURI();
if (currentNamespace == MathMLNames::mathmlNamespaceURI)
adjustMathMLAttributes(token);
if (currentNamespace == SVGNames::svgNamespaceURI) {
adjustSVGTagNameCase(token);
adjustSVGAttributes(token);
}
adjustForeignAttributes(token);
m_tree.insertForeignElement(token, currentNamespace);
break;
}
case TextMode:
ASSERT_NOT_REACHED();
break;
}
}

14,HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken& token)

 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken& token)
{
m_openElements.push(attachToCurrent(createHTMLElement(token)));
}

15,HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)

 PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)
{
return attach(currentNode(), child);
}

16,HTMLConstructionSite::attach(ContainerNode* rawParent, PassRefPtr<ChildType> prpChild)

 template<typename ChildType>
PassRefPtr<ChildType> HTMLConstructionSite::attach(ContainerNode* rawParent, PassRefPtr<ChildType> prpChild)
{
RefPtr<ChildType> child = prpChild;
RefPtr<ContainerNode> parent = rawParent; // FIXME: It's confusing that HTMLConstructionSite::attach does the magic
// redirection to the foster parent but HTMLConstructionSite::attachAtSite
// doesn't. It feels like we're missing a concept somehow.
if (shouldFosterParent()) {
fosterParent(child.get());
ASSERT(child->attached() || !child->parentNode() || !child->parentNode()->attached());
return child.release();
} parent->parserAddChild(child); // An event handler (DOM Mutation, beforeload, et al.) could have removed
// the child, in which case we shouldn't try attaching it.
if (!child->parentNode())
return child.release(); if (parent->attached() && !child->attached())
child->attach();
return child.release();
}

17,ContainerNode::parserAddChild(PassRefPtr<Node> newChild)

 void ContainerNode::parserAddChild(PassRefPtr<Node> newChild)
{
ASSERT(newChild);
ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events). #if ENABLE(INSPECTOR)
InspectorInstrumentation::willInsertDOMNode(document(), newChild.get(), this);
#endif forbidEventDispatch();
Node* last = m_lastChild;
// FIXME: This method should take a PassRefPtr.
appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
newChild->setTreeScopeRecursively(treeScope()); allowEventDispatch(); // FIXME: Why doesn't this use notifyChildInserted(newChild) instead?
document()->incDOMTreeVersion();
if (inDocument())
newChild->insertedIntoDocument();
childrenChanged(true, last, , );
}

18,ContainerNode::insertedIntoDocument()

 void ContainerNode::insertedIntoDocument()
{
RefPtr<Node> protect(this); Node::insertedIntoDocument();
insertedIntoTree(false); for (RefPtr<Node> child = m_firstChild; child; child = child->nextSibling()) {
// Guard against mutation during re-parenting.
if (!inDocument()) // Check for self being removed from document while reparenting.
break;
if (child->parentNode() != this) // Check for child being removed from subtree while reparenting.
break;
child->insertedIntoDocument();
}
}

19,HTMLFrameElementBase::insertedIntoDocument()

 void HTMLFrameElementBase::insertedIntoDocument()
{
HTMLFrameOwnerElement::insertedIntoDocument(); if (m_remainsAliveOnRemovalFromTree) {
updateOnReparenting();
setRemainsAliveOnRemovalFromTree(false);
return;
}
// DocumentFragments don't kick of any loads.
if (!document()->frame())
return; // Loads may cause synchronous javascript execution (e.g. beforeload or
// src=javascript), which could try to access the renderer before the normal
// parser machinery would call lazyAttach() and set us as needing style
// resolve. Any code which expects this to be attached will resolve style
// before using renderer(), so this will make sure we attach in time.
// FIXME: Normally lazyAttach marks the renderer as attached(), but we don't
// want to do that here, as as callers expect to call attach() right after
// this and attach() will ASSERT(!attached())
ASSERT(!renderer()); // This recalc is unecessary if we already have a renderer.
lazyAttach(DoNotSetAttached);
setNameAndOpenURL();
}

20,HTMLFrameElementBase::setNameAndOpenURL()

 void HTMLFrameElementBase::setNameAndOpenURL()
{
m_frameName = getAttribute(nameAttr);
if (m_frameName.isNull())
m_frameName = getIdAttribute();
openURL();
}

21,HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList)

 void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList)
{
if (!isURLAllowed())
return; if (m_URL.isEmpty())
m_URL = blankURL().string(); Frame* parentFrame = document()->frame();
if (!parentFrame)
return; parentFrame->loader()->subframeLoader()->requestFrame(this, m_URL, m_frameName, lockHistory, lockBackForwardList);
if (contentFrame())
contentFrame()->setInViewSourceMode(viewSourceMode());
}

22,SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)

 bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
{
// Support for <frame src="javascript:string">
KURL scriptURL;
KURL url;
if (protocolIsJavaScript(urlString)) {
scriptURL = completeURL(urlString); // completeURL() encodes the URL.
url = blankURL();
} else
url = completeURL(urlString); Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
if (!frame)
return false; if (!scriptURL.isEmpty())
frame->script()->executeIfJavaScriptURL(scriptURL); return true;
}

23,SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)

 Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
{
Frame* frame = ownerElement->contentFrame();
if (frame)
frame->navigationScheduler()->scheduleLocationChange(m_frame->document()->securityOrigin(), url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);
else
frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
return frame;
}

24,SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)

 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
{
bool allowsScrolling = true;
int marginWidth = -;
int marginHeight = -;
if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
marginWidth = o->marginWidth();
marginHeight = o->marginHeight();
} if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
FrameLoader::reportLocalLoadFailed(m_frame, url.string());
return ;
} if (!ownerElement->document()->contentSecurityPolicy()->allowChildFrameFromSource(url))
return ; bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight); if (!frame) {
m_frame->loader()->checkCallImplicitClose();
return ;
} // All new frames will have m_isComplete set to true at this point due to synchronously loading
// an empty document in FrameLoader::init(). But many frames will now be starting an
// asynchronous load of url, so we set m_isComplete to false and then check if the load is
// actually completed below. (Note that we set m_isComplete to false even for synchronous
// loads, so that checkCompleted() below won't bail early.)
// FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
frame->loader()->started(); RenderObject* renderer = ownerElement->renderer();
FrameView* view = frame->view();
if (renderer && renderer->isWidget() && view)
toRenderWidget(renderer)->setWidget(view); m_frame->loader()->checkCallImplicitClose(); // Some loads are performed synchronously (e.g., about:blank and loads
// cancelled by returning a null ResourceRequest from requestFromDelegate).
// In these cases, the synchronous load would have finished
// before we could connect the signals, so make sure to send the
// completed() signal for the child by hand and mark the load as being
// complete.
// FIXME: In this case the Frame will have finished loading before
// it's being added to the child list. It would be a good idea to
// create the child first, then invoke the loader separately.
if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
frame->loader()->checkCompleted(); return frame.get();
}

25,FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)

 PassRefPtr<Frame> FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
{
if (!m_webFrame)
return ; QWebFrameData frameData(m_frame->page(), m_frame, ownerElement, name); if (url.isEmpty())
frameData.url = blankURL();
else
frameData.url = url; frameData.referrer = referrer;
frameData.allowsScrolling = allowsScrolling;
frameData.marginWidth = marginWidth;
frameData.marginHeight = marginHeight; QPointer<QWebFrame> webFrame = new QWebFrame(m_webFrame, &frameData);
// The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
if (!webFrame->d->frame->page()) {
frameData.frame.release();
ASSERT(webFrame.isNull());
return ;
} emit m_webFrame->page()->frameCreated(webFrame); // FIXME: Set override encoding if we have one. m_frame->loader()->loadURLIntoChildFrame(frameData.url, frameData.referrer, frameData.frame.get()); // The frame's onload handler may have removed it from the document.
if (!frameData.frame->tree()->parent())
return ; return frameData.frame.release();
}

26,QWebFrameData::QWebFrameData(... )

 QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame,
WebCore::HTMLFrameOwnerElement* ownerFrameElement,
const WTF::String& frameName)
: name(frameName)
, ownerElement(ownerFrameElement)
, page(parentPage)
, allowsScrolling(true)
, marginWidth()
, marginHeight()
{
frameLoaderClient = new FrameLoaderClientQt();
frame = Frame::create(page, ownerElement, frameLoaderClient); // FIXME: All of the below should probably be moved over into WebCore
frame->tree()->setName(name);
if (parentFrame)
parentFrame->tree()->appendChild(frame);
}

OK,代码量太庞大了,至此,代码跟踪完成!!!

3.2  createView

         void createView(const IntSize&, const Color&, bool, const IntSize&, bool,
ScrollbarMode = ScrollbarAuto, bool horizontalLock = false,
ScrollbarMode = ScrollbarAuto, bool verticalLock = false);

描述:
      创建出FrameView对象,以用于之后的排版。应用调用这个函数的时候需要传入同排版有关的一些信息,如初始 视窗大小、背景色、滚动条模式等。创建出FrameView以后,即调用Frame::setView设置成当前的FrameView。

实现:

 void Frame::setView(PassRefPtr<FrameView> view)
{
// We the custom scroll bars as early as possible to prevent m_doc->detach()
// from messing with the view such that its scroll bars won't be torn down.
// FIXME: We should revisit this.
if (m_view)
m_view->detachCustomScrollbars(); // Detach the document now, so any onUnload handlers get run - if
// we wait until the view is destroyed, then things won't be
// hooked up enough for some JavaScript calls to work.
if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
// FIXME: We don't call willRemove here. Why is that OK?
m_doc->detach();
} if (m_view)
m_view->unscheduleRelayout(); eventHandler()->clear(); m_view = view; // Only one form submission is allowed per view of a part.
// Since this part may be getting reused as a result of being
// pulled from the back/forward cache, reset this flag.
loader()->resetMultipleFormSubmissionProtection(); #if ENABLE(TILED_BACKING_STORE)
if (m_view && tiledBackingStore())
m_view->setPaintsEntireContents(true);
#endif
}

函数调用系列:

 FrameLoader::commitProvisionalLoad
FrameLoader::transitionToCommitted
FrameLoaderClientQt::transitionToCommittedForNewPage
Frame::createView

跟踪一下代码(同上)
1,QWebView::load(const QUrl &url)

 void QWebView::load(const QUrl &url)
{
page()->mainFrame()->load(url);
}

2,QWebFrame::load(const QNetworkRequest &req,QNetworkAccessManager::Operation operation,const QByteArray &body)

 void QWebFrame::load(const QNetworkRequest &req,
QNetworkAccessManager::Operation operation,
const QByteArray &body)
{
if (d->parentFrame())
d->page->d->insideOpenCall = true; QUrl url = ensureAbsoluteUrl(req.url()); WebCore::ResourceRequest request(url); switch (operation) {
case QNetworkAccessManager::HeadOperation:
request.setHTTPMethod("HEAD");
break;
case QNetworkAccessManager::GetOperation:
request.setHTTPMethod("GET");
break;
case QNetworkAccessManager::PutOperation:
request.setHTTPMethod("PUT");
break;
case QNetworkAccessManager::PostOperation:
request.setHTTPMethod("POST");
break;
case QNetworkAccessManager::DeleteOperation:
request.setHTTPMethod("DELETE");
break;
case QNetworkAccessManager::CustomOperation:
request.setHTTPMethod(req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray().constData());
break;
case QNetworkAccessManager::UnknownOperation:
// eh?
break;
} QVariant cacheLoad = req.attribute(QNetworkRequest::CacheLoadControlAttribute);
if (cacheLoad.isValid()) {
bool ok;
uint cacheLoadValue = cacheLoad.toUInt(&ok);
if (ok)
request.setCachePolicy(cacheLoadControlToCachePolicy(cacheLoadValue));
} QList<QByteArray> httpHeaders = req.rawHeaderList();
for (int i = ; i < httpHeaders.size(); ++i) {
const QByteArray &headerName = httpHeaders.at(i);
request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
} if (!body.isEmpty())
request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size())); d->frame->loader()->load(request, false); if (d->parentFrame())
d->page->d->insideOpenCall = false;
}

3, FrameLoader::load(const ResourceRequest& request, bool lockHistory)

 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
{
load(request, SubstituteData(), lockHistory);
}

4,FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)

 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
{
if (m_inStopAllLoaders)
return; // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
m_loadType = FrameLoadTypeStandard;
RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
if (lockHistory && m_documentLoader)
loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
load(loader.get());
}

5,FrameLoader::load(DocumentLoader* newDocumentLoader)

 void FrameLoader::load(DocumentLoader* newDocumentLoader)
{
ResourceRequest& r = newDocumentLoader->request();
addExtraFieldsToMainResourceRequest(r);
FrameLoadType type; if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
r.setCachePolicy(ReloadIgnoringCacheData);
type = FrameLoadTypeSame;
} else
type = FrameLoadTypeStandard; if (m_documentLoader)
newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding()); // When we loading alternate content for an unreachable URL that we're
// visiting in the history list, we treat it as a reload so the history list
// is appropriately maintained.
//
// FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
// shouldn't a more explicit type of reload be defined, that means roughly
// "load without affecting history" ?
if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
// shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.
// In this case we should save the document state now. Otherwise the state can be lost because load type is
// changed and updateForBackForwardNavigation() will not be called when loading is committed.
history()->saveDocumentAndScrollState(); ASSERT(type == FrameLoadTypeStandard);
type = FrameLoadTypeReload;
} loadWithDocumentLoader(newDocumentLoader, type, 0);
}

6,FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)

 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
{
// Retain because dispatchBeforeLoadEvent may release the last reference to it.
RefPtr<Frame> protect(m_frame); ASSERT(m_client->hasWebView()); // Unfortunately the view must be non-nil, this is ultimately due
// to parser requiring a FrameView. We should fix this dependency. ASSERT(m_frame->view()); if (m_pageDismissalEventBeingDispatched)
return; if (m_frame->document())
m_previousUrl = m_frame->document()->url(); policyChecker()->setLoadType(type);
RefPtr<FormState> formState = prpFormState;
bool isFormSubmission = formState; const KURL& newURL = loader->request().url();
const String& httpMethod = loader->request().httpMethod(); if (shouldScrollToAnchor(isFormSubmission, httpMethod, policyChecker()->loadType(), newURL)) {
RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
NavigationAction action(newURL, policyChecker()->loadType(), isFormSubmission); oldDocumentLoader->setTriggeringAction(action);
policyChecker()->stopCheck();
policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
callContinueFragmentScrollAfterNavigationPolicy, this);
} else {
if (Frame* parent = m_frame->tree()->parent())
loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding()); policyChecker()->stopCheck();
setPolicyDocumentLoader(loader);
if (loader->triggeringAction().isEmpty())
loader->setTriggeringAction(NavigationAction(newURL, policyChecker()->loadType(), isFormSubmission)); if (Element* ownerElement = m_frame->ownerElement()) {
// We skip dispatching the beforeload event if we've already
// committed a real document load because the event would leak
// subsequent activity by the frame which the parent frame isn't
// supposed to learn. For example, if the child frame navigated to
// a new URL, the parent frame shouldn't learn the URL.
if (!m_stateMachine.committedFirstRealDocumentLoad()
&& !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {
continueLoadAfterNavigationPolicy(loader->request(), formState, false);
return;
}
} policyChecker()->checkNavigationPolicy(loader->request(), loader, formState,
callContinueLoadAfterNavigationPolicy, this);
}
}

7,FrameLoader::callContinueLoadAfterNavigationPolicy( ... )

 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
{
FrameLoader* loader = static_cast<FrameLoader*>(argument);
loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
}

8,FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)

 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
{
// If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
// nil policyDataSource because loading the alternate page will have passed
// through this method already, nested; otherwise, policyDataSource should still be set.
ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty()); bool isTargetItem = history()->provisionalItem() ? history()->provisionalItem()->isTargetItem() : false; // Two reasons we can't continue:
// 1) Navigation policy delegate said we can't so request is nil. A primary case of this
// is the user responding Cancel to the form repost nag sheet.
// 2) User responded Cancel to an alert popped up by the before unload event handler.
bool canContinue = shouldContinue && shouldClose(); if (!canContinue) {
// If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
// need to report that the client redirect was cancelled.
if (m_quickRedirectComing)
clientRedirectCancelledOrFinished(false); setPolicyDocumentLoader(); // If the navigation request came from the back/forward menu, and we punt on it, we have the
// problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
// we only do this when punting a navigation for the target frame or top-level frame.
if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType())) {
if (Page* page = m_frame->page()) {
Frame* mainFrame = page->mainFrame();
if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) {
page->backForward()->setCurrentItem(resetItem);
m_frame->loader()->client()->updateGlobalHistoryItemForPage();
}
}
}
return;
} FrameLoadType type = policyChecker()->loadType();
// A new navigation is in progress, so don't clear the history's provisional item.
stopAllLoaders(ShouldNotClearProvisionalItem); // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()
// might detach the current FrameLoader, in which case we should bail on this newly defunct load.
if (!m_frame->page())
return; #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) && ENABLE(INSPECTOR)
if (Page* page = m_frame->page()) {
if (page->mainFrame() == m_frame)
m_frame->page()->inspectorController()->resume();
}
#endif setProvisionalDocumentLoader(m_policyDocumentLoader.get());
m_loadType = type;
setState(FrameStateProvisional); setPolicyDocumentLoader(); if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) {
loadProvisionalItemFromCachedPage();
return;
} if (formState)
m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);
else
continueLoadAfterWillSubmitForm();
}

9,FrameLoader::loadProvisionalItemFromCachedPage()

 void FrameLoader::loadProvisionalItemFromCachedPage()
{
DocumentLoader* provisionalLoader = provisionalDocumentLoader();
LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().string().utf8().data()); provisionalLoader->prepareForLoadStart(); m_loadingFromCachedPage = true; // Should have timing data from previous time(s) the page was shown.
ASSERT(provisionalLoader->timing()->navigationStart);
provisionalLoader->resetTiming();
provisionalLoader->timing()->navigationStart = currentTime(); provisionalLoader->setCommitted(true);
commitProvisionalLoad();
}

10,FrameLoader::commitProvisionalLoad()

 void FrameLoader::commitProvisionalLoad()
{
RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : ;
RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(),
m_frame->document() ? m_frame->document()->url().string().utf8().data() : "",
pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>"); // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
// We are doing this here because we know for sure that a new page is about to be loaded.
HistoryItem* item = history()->currentItem();
if (!m_frame->tree()->parent() && PageCache::canCache(m_frame->page()) && !item->isInPageCache())
pageCache()->add(item, m_frame->page()); if (m_loadType != FrameLoadTypeReplace)
closeOldDataSources(); if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
m_client->makeRepresentation(pdl.get()); transitionToCommitted(cachedPage); if (pdl) {
// Check if the destination page is allowed to access the previous page's timing information.
RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
m_documentLoader->timing()->hasSameOriginAsPreviousDocument = securityOrigin->canRequest(m_previousUrl);
} // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
// status has changed, if there was a redirect. The frame load delegate may have saved some state about
// the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
// just about to commit a new page, there cannot possibly be a pending redirect at this point.
if (m_sentRedirectNotification)
clientRedirectCancelledOrFinished(false); if (cachedPage && cachedPage->document()) {
prepareForCachedPageRestore();
cachedPage->restore(m_frame->page()); dispatchDidCommitLoad(); // If we have a title let the WebView know about it.
StringWithDirection title = m_documentLoader->title();
if (!title.isNull())
m_client->dispatchDidReceiveTitle(title); checkCompleted();
} else {
KURL url = pdl->substituteData().responseURL();
if (url.isEmpty())
url = pdl->url();
if (url.isEmpty())
url = pdl->responseURL();
if (url.isEmpty())
url = blankURL(); didOpenURL(url);
} LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(),
m_frame->document() ? m_frame->document()->url().string().utf8().data() : ""); if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
history()->updateForClientRedirect(); if (m_loadingFromCachedPage) {
m_frame->document()->documentDidBecomeActive(); // Force a layout to update view size and thereby update scrollbars.
m_frame->view()->forceLayout(); const ResponseVector& responses = m_documentLoader->responses();
size_t count = responses.size();
for (size_t i = ; i < count; i++) {
const ResourceResponse& response = responses[i];
// FIXME: If the WebKit client changes or cancels the request, this is not respected.
ResourceError error;
unsigned long identifier;
ResourceRequest request(response.url());
requestFromDelegate(request, identifier, error);
// FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
// However, with today's computers and networking speeds, this won't happen in practice.
// Could be an issue with a giant local file.
notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, static_cast<int>(response.expectedContentLength()), , error);
} pageCache()->remove(history()->currentItem()); m_documentLoader->setPrimaryLoadComplete(true); // FIXME: Why only this frame and not parent frames?
checkLoadCompleteForThisFrame();
}
}

11,FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)

 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
{
ASSERT(m_client->hasWebView());
ASSERT(m_state == FrameStateProvisional); if (m_state != FrameStateProvisional)
return; if (m_frame->view())
m_frame->view()->scrollAnimator()->cancelAnimations(); m_client->setCopiesOnScroll();
history()->updateForCommit(); // The call to closeURL() invokes the unload event handler, which can execute arbitrary
// JavaScript. If the script initiates a new load, we need to abandon the current load,
// or the two will stomp each other.
DocumentLoader* pdl = m_provisionalDocumentLoader.get();
if (m_documentLoader)
closeURL();
if (pdl != m_provisionalDocumentLoader)
return; // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
if (m_documentLoader)
m_documentLoader->stopLoadingSubresources();
if (m_documentLoader)
m_documentLoader->stopLoadingPlugIns(); setDocumentLoader(m_provisionalDocumentLoader.get());
setProvisionalDocumentLoader();
setState(FrameStateCommittedPage); // Handle adding the URL to the back/forward list.
DocumentLoader* dl = m_documentLoader.get(); switch (m_loadType) {
case FrameLoadTypeForward:
case FrameLoadTypeBack:
case FrameLoadTypeIndexedBackForward:
if (m_frame->page()) {
// If the first load within a frame is a navigation within a back/forward list that was attached
// without any of the items being loaded then we need to update the history in a similar manner as
// for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
if (!m_stateMachine.committedFirstRealDocumentLoad())
history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList); history()->updateForBackForwardNavigation(); // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
if (history()->currentItem() && !cachedPage)
m_pendingStateObject = history()->currentItem()->stateObject(); // Create a document view for this document, or used the cached view.
if (cachedPage) {
DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
ASSERT(cachedDocumentLoader);
cachedDocumentLoader->setFrame(m_frame);
m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame()); } else
m_client->transitionToCommittedForNewPage();
}
break; case FrameLoadTypeReload:
case FrameLoadTypeReloadFromOrigin:
case FrameLoadTypeSame:
case FrameLoadTypeReplace:
history()->updateForReload();
m_client->transitionToCommittedForNewPage();
break; case FrameLoadTypeStandard:
history()->updateForStandardLoad();
if (m_frame->view())
m_frame->view()->setScrollbarsSuppressed(true);
m_client->transitionToCommittedForNewPage();
break; case FrameLoadTypeRedirectWithLockedBackForwardList:
history()->updateForRedirectWithLockedBackForwardList();
m_client->transitionToCommittedForNewPage();
break; // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
// An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
default:
ASSERT_NOT_REACHED();
} m_documentLoader->writer()->setMIMEType(dl->responseMIMEType()); // Tell the client we've committed this URL.
ASSERT(m_frame->view()); if (m_stateMachine.creatingInitialEmptyDocument())
return; if (!m_stateMachine.committedFirstRealDocumentLoad())
m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit); if (!m_client->hasHTMLView())
receivedFirstData();
}

12,FrameLoaderClientQt::transitionToCommittedForNewPage()

 void FrameLoaderClientQt::transitionToCommittedForNewPage()
{
ASSERT(m_frame);
ASSERT(m_webFrame); QBrush brush = m_webFrame->page()->palette().brush(QPalette::Base);
QColor backgroundColor = brush.style() == Qt::SolidPattern ? brush.color() : QColor(); QWebPage* page = m_webFrame->page();
const QSize preferredLayoutSize = page->preferredContentsSize(); ScrollbarMode hScrollbar = (ScrollbarMode) m_webFrame->scrollBarPolicy(Qt::Horizontal);
ScrollbarMode vScrollbar = (ScrollbarMode) m_webFrame->scrollBarPolicy(Qt::Vertical);
bool hLock = hScrollbar != ScrollbarAuto;
bool vLock = vScrollbar != ScrollbarAuto; IntSize currentVisibleContentSize = m_frame->view() ? m_frame->view()->actualVisibleContentRect().size() : IntSize(); m_frame->createView(m_webFrame->page()->viewportSize(),
20 backgroundColor, !backgroundColor.alpha(),
21 preferredLayoutSize.isValid() ? IntSize(preferredLayoutSize) : IntSize(),
22 preferredLayoutSize.isValid(),
23 hScrollbar, hLock,
24 vScrollbar, vLock); bool isMainFrame = m_frame == m_frame->page()->mainFrame();
if (isMainFrame && page->d->client) {
m_frame->view()->setPaintsEntireContents(page->d->client->viewResizesToContentsEnabled());
m_frame->view()->setDelegatesScrolling(page->d->client->viewResizesToContentsEnabled());
} // The HistoryController will update the scroll position later if needed.
m_frame->view()->setActualVisibleContentRect(IntRect(IntPoint::zero(), currentVisibleContentSize));
}

13,Frame::createView( ... )

14,Frame::setView(PassRefPtr<FrameView> view)

 void Frame::setView(PassRefPtr<FrameView> view)
{
// We the custom scroll bars as early as possible to prevent m_doc->detach()
// from messing with the view such that its scroll bars won't be torn down.
// FIXME: We should revisit this.
if (m_view)
m_view->detachCustomScrollbars(); // Detach the document now, so any onUnload handlers get run - if
// we wait until the view is destroyed, then things won't be
// hooked up enough for some JavaScript calls to work.
if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
// FIXME: We don't call willRemove here. Why is that OK?
m_doc->detach();
} if (m_view)
m_view->unscheduleRelayout(); eventHandler()->clear(); m_view = view; // Only one form submission is allowed per view of a part.
// Since this part may be getting reused as a result of being
// pulled from the back/forward cache, reset this flag.
loader()->resetMultipleFormSubmissionProtection(); #if ENABLE(TILED_BACKING_STORE)
if (m_view && tiledBackingStore())
m_view->setPaintsEntireContents(true);
#endif
}

OK!!! CreateView代码跟踪到此为止!!

3.3 setDocument

 void setDocument(PassRefPtr<Document>);

描述:

    置同Frame关联的Document对象(一般是DocumentWriter创建的)。还是两种情况

实现:

 void Frame::setDocument(PassRefPtr<Document> newDoc)
{
ASSERT(!newDoc || newDoc->frame());
if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
// FIXME: We don't call willRemove here. Why is that OK?
m_doc->detach();
} m_doc = newDoc;
selection()->updateSecureKeyboardEntryIfActive(); if (m_doc && !m_doc->attached())
m_doc->attach(); // Update the cached 'document' property, which is now stale.
m_script.updateDocument(); if (m_page)
m_page->updateViewportArguments();
}

函数调用系列:

 QWebFrame::QwebFrame
QwebFramePrivate::init
Frame::init
FrameLoader::init
DocumentWriter::begin
Frame::setDocument DocumentLoader::receivedData
DocumentLoader::commitLoad
FrameLoaderClientQt::committedLoad
DocumentLoader::commitData
DocumentWriter::setEncoding
DocumentWriter::willSetEncoding
FrameLoader::receivedFirstData
DocumentWriter::begin
FrameLoader::clear
Frame::setDocument

代码跟踪(分两种)
情况一:

1,QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)

 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
: QObject(parent)
, d(new QWebFramePrivate)
{
d->page = parent->d->page;
d->init(this, frameData);
#if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
d->m_orientation.start();
#endif
}

2,QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)

 void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)
{
q = qframe; allowsScrolling = frameData->allowsScrolling;
marginWidth = frameData->marginWidth;
marginHeight = frameData->marginHeight;
frame = frameData->frame.get();
frameLoaderClient = frameData->frameLoaderClient;
frameLoaderClient->setFrame(qframe, frame); frame->init();
}

3,Frame::init()

  inline void Frame::init()
{
m_loader.init();
}

4,FrameLoader::init()

 void FrameLoader::init()
{
// Propagate sandbox attributes to this Frameloader and its descendants.
// This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
updateSandboxFlags(); // this somewhat odd set of steps is needed to give the frame an initial empty document
m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
setProvisionalDocumentLoader(m_policyDocumentLoader.get());
setState(FrameStateProvisional);
m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", , String(), String()));
m_provisionalDocumentLoader->finishedLoading();
m_documentLoader->writer()->begin(KURL(), false);
m_documentLoader->writer()->end();
m_frame->document()->cancelParsing();
m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
m_didCallImplicitClose = true; m_networkingContext = m_client->createNetworkingContext();
}

5,DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin)

 void DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin)
{
// We need to take a reference to the security origin because |clear|
// might destroy the document that owns it.
RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; // We grab a local copy of the URL because it's easy for callers to supply
// a URL that will be deallocated during the execution of this function.
// For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
KURL url = urlReference; // Create a new document before clearing the frame, because it may need to
// inherit an aliased security context.
RefPtr<Document> document = createDocument(url); // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
// then replace the document with one whose parser will ignore the incoming data (bug 39323)
if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))
document = SinkDocument::create(m_frame, url); // FIXME: Do we need to consult the content security policy here about blocked plug-ins? bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
m_frame->loader()->clear(resetScripting, resetScripting);
clear();
if (resetScripting)
m_frame->script()->updatePlatformScriptObjects(); m_frame->loader()->setOutgoingReferrer(url);
m_frame->setDocument(document); if (m_decoder)
document->setDecoder(m_decoder.get());
if (forcedSecurityOrigin)
document->setSecurityOrigin(forcedSecurityOrigin.get()); m_frame->domWindow()->setURL(document->url());
m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); m_frame->loader()->didBeginDocument(dispatch); document->implicitOpen(); if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
m_frame->view()->setContentsSize(IntSize());
}

6,Frame::setDocument(PassRefPtr<Document> newDoc)

情况二:

1,MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)

 void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
{
ASSERT(data);
ASSERT(length != ); ASSERT(!m_response.isNull()); #if USE(CFNETWORK) || PLATFORM(MAC)
// Workaround for <rdar://problem/6060782>
if (m_response.isNull()) {
m_response = ResourceResponse(KURL(), "text/html", , String(), String());
if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader())
documentLoader->setResponse(m_response);
}
#endif // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
// See <rdar://problem/6304600> for more details.
#if !USE(CF)
ASSERT(!defersLoading());
#endif #if ENABLE(OFFLINE_WEB_APPLICATIONS)
documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce);
#endif // The additional processing can do anything including possibly removing the last
// reference to this object; one example of this is 3266216.
RefPtr<MainResourceLoader> protect(this); m_timeOfLastDataReceived = currentTime(); ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
}

2,ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)

 void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
{
// The following assertions are not quite valid here, since a subclass
// might override didReceiveData in a way that invalidates them. This
// happens with the steps listed in 3266216
// ASSERT(con == connection);
// ASSERT(!m_reachedTerminalState); // Protect this in this delegate method since the additional processing can do
// anything including possibly derefing this; one example of this is Radar 3266216.
RefPtr<ResourceLoader> protector(this); addData(data, length, allAtOnce);
// FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
// However, with today's computers and networking speeds, this won't happen in practice.
// Could be an issue with a giant local file.
if (m_sendResourceLoadCallbacks && m_frame)
frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength));
}

3,MainResourceLoader::addData(const char* data, int length, bool allAtOnce)

 void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
{
ResourceLoader::addData(data, length, allAtOnce);
documentLoader()->receivedData(data, length);
}

4,DocumentLoader::receivedData(const char* data, int length)

 void DocumentLoader::receivedData(const char* data, int length)
{
m_gotFirstByte = true;
if (doesProgressiveLoad(m_response.mimeType()))
commitLoad(data, length);
}

5,DocumentLoader::commitLoad(const char* data, int length)

 void DocumentLoader::commitLoad(const char* data, int length)
{
// Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
// by starting a new load, so retain temporarily.
RefPtr<Frame> protectFrame(m_frame);
RefPtr<DocumentLoader> protectLoader(this); commitIfReady();
FrameLoader* frameLoader = DocumentLoader::frameLoader();
if (!frameLoader)
return;
#if ENABLE(WEB_ARCHIVE)
if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
return;
#endif
frameLoader->client()->committedLoad(this, data, length);
}

6,FrameLoaderClientQt::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)

 void FrameLoaderClientQt::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)
{
if (!m_pluginView)
loader->commitData(data, length); // We re-check here as the plugin can have been created.
if (m_pluginView && m_pluginView->isPluginView()) {
if (!m_hasSentResponseToPlugin) {
m_pluginView->didReceiveResponse(loader->response());
// The function didReceiveResponse sets up a new stream to the plug-in.
// On a full-page plug-in, a failure in setting up this stream can cause the
// main document load to be cancelled, setting m_pluginView to null.
if (!m_pluginView)
return;
m_hasSentResponseToPlugin = true;
}
m_pluginView->didReceiveData(data, length);
}
}

7,DocumentLoader::commitData(const char* bytes, int length)

 void DocumentLoader::commitData(const char* bytes, int length)
{
// Set the text encoding. This is safe to call multiple times.
bool userChosen = true;
String encoding = overrideEncoding();
if (encoding.isNull()) {
userChosen = false;
encoding = response().textEncodingName();
}
m_writer.setEncoding(encoding, userChosen);
ASSERT(m_frame->document()->parsing());
m_writer.addData(bytes, length);
}

8,DocumentWriter::setEncoding(const String& name, bool userChosen)

 void DocumentWriter::setEncoding(const String& name, bool userChosen)
{
m_frame->loader()->willSetEncoding();
m_encoding = name;
m_encodingWasChosenByUser = userChosen;
}

9,FrameLoader::willSetEncoding()

 void FrameLoader::willSetEncoding()
{
if (!m_workingURL.isEmpty())
receivedFirstData();
}

10,FrameLoader::receivedFirstData()

 void FrameLoader::receivedFirstData()
{
activeDocumentLoader()->writer()->begin(m_workingURL, false);
activeDocumentLoader()->writer()->setDocumentWasLoadedAsPartOfNavigation(); dispatchDidCommitLoad();
dispatchDidClearWindowObjectsInAllWorlds(); if (m_documentLoader) {
StringWithDirection ptitle = m_documentLoader->title();
// If we have a title let the WebView know about it.
if (!ptitle.isNull())
m_client->dispatchDidReceiveTitle(ptitle);
} m_workingURL = KURL(); double delay;
String url;
if (!m_documentLoader)
return;
if (m_frame->inViewSourceMode())
return;
if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
return; if (url.isEmpty())
url = m_frame->document()->url().string();
else
url = m_frame->document()->completeURL(url).string(); m_frame->navigationScheduler()->scheduleRedirect(delay, url);
}

11,DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin)

 void DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin)
{
// We need to take a reference to the security origin because |clear|
// might destroy the document that owns it.
RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; // We grab a local copy of the URL because it's easy for callers to supply
// a URL that will be deallocated during the execution of this function.
// For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
KURL url = urlReference; // Create a new document before clearing the frame, because it may need to
// inherit an aliased security context.
RefPtr<Document> document = createDocument(url); // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
// then replace the document with one whose parser will ignore the incoming data (bug 39323)
if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))
document = SinkDocument::create(m_frame, url); // FIXME: Do we need to consult the content security policy here about blocked plug-ins? bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
m_frame->loader()->clear(resetScripting, resetScripting);
clear();
if (resetScripting)
m_frame->script()->updatePlatformScriptObjects(); m_frame->loader()->setOutgoingReferrer(url);
m_frame->setDocument(document); if (m_decoder)
document->setDecoder(m_decoder.get());
if (forcedSecurityOrigin)
document->setSecurityOrigin(forcedSecurityOrigin.get()); m_frame->domWindow()->setURL(document->url());
m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); m_frame->loader()->didBeginDocument(dispatch); document->implicitOpen(); if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
m_frame->view()->setContentsSize(IntSize());
}

12,FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)

 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
{
m_frame->editor()->clear(); if (!m_needsClear)
return;
m_needsClear = false; if (!m_frame->document()->inPageCache()) {
m_frame->document()->cancelParsing();
m_frame->document()->stopActiveDOMObjects();
if (m_frame->document()->attached()) {
m_frame->document()->willRemove();
m_frame->document()->detach(); m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
}
} // Do this after detaching the document so that the unload event works.
if (clearWindowProperties) {
m_frame->clearDOMWindow();
m_frame->script()->clearWindowShell(m_frame->document()->inPageCache());
} m_frame->selection()->clear();
m_frame->eventHandler()->clear();
if (clearFrameView && m_frame->view())
m_frame->view()->clear(); // Do not drop the document before the ScriptController and view are cleared
// as some destructors might still try to access the document.
m_frame->setDocument(0); m_subframeLoader.clear(); if (clearScriptObjects)
m_frame->script()->clearScriptObjects(); m_frame->navigationScheduler()->clear(); m_checkTimer.stop();
m_shouldCallCheckCompleted = false;
m_shouldCallCheckLoadComplete = false; if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
}

13,Frame::setDocument(PassRefPtr<Document> newDoc)

OK! setDocuemnt源码跟踪到此为止!

3.4 init

 void init();

描述:

Frame对象初始化,会调用 FrameLoader::init 初始化FrameLoader对象

实现:

     inline void Frame::init()
{
m_loader.init();
}

调用系列:

 QWebFrame::QWebFrame
QwebFramePrivate::init
Frame::init

代码已经跟踪过,见上面

3.5 setPageAndTextZoomFactors

 void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor);

描述:

设置页面放大因子和文字放大因子。在网页缩放或者改变网页字体大小的时候调用

实现:

 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
{
if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
return; Page* page = this->page();
if (!page)
return; Document* document = this->document();
if (!document)
return; m_editor.dismissCorrectionPanelAsIgnored(); #if ENABLE(SVG)
// Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
// FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
if (document->isSVGDocument()) {
if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
return;
if (document->renderer())
document->renderer()->setNeedsLayout(true);
}
#endif if (m_pageZoomFactor != pageZoomFactor) {
if (FrameView* view = this->view()) {
// Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
IntPoint scrollPosition = view->scrollPosition();
float percentDifference = (pageZoomFactor / m_pageZoomFactor);
view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
}
} m_pageZoomFactor = pageZoomFactor;
m_textZoomFactor = textZoomFactor; document->recalcStyle(Node::Force); for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor); if (FrameView* view = this->view()) {
if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
view->layout();
}
}

OK!!!! 完结

webkit内核分析之 Frame的更多相关文章

  1. WebKit内核分析之Page

    参考地址:http://blog.csdn.net/dlmu2001/article/details/6213377 注:本系列博客是在原博主博客基础上增加了自己的理解和片段,可以看源博文获得清晰的结 ...

  2. WebKit内核分析之FrameLoader

    参考地址:http://blog.csdn.net/dlmu2001/article/details/6168545 FrameLoader类负责一个Frame的加载,在Frame的流程中起到非常重要 ...

  3. [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

    [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...

  4. css3中-moz、-ms、-webkit,-o分别代表的意思,以及微信浏览器内核分析

    这种方式在业界上统称:识别码.前缀 //-ms代表[ie]内核识别码 //-moz代表火狐[firefox]内核识别码 //-webkit代表谷歌[chrome]/苹果[safari]内核识别码 // ...

  5. iOS:WebKit内核框架的应用与解析

    原文:http://www.cnblogs.com/fengmin/p/5737355.html 一.摘要: WebKit是iOS8之后引入的专门负责处理网页视图的框架,其比UIWebView更加强大 ...

  6. IE8+等兼容、360调用webkit内核小记

    首先是处理IE8.9等的兼容问题,注意以下几点: 1,尽可能严格要求自己使用w3c推荐的方式编写html/css 2,在html页面顶部添加<!DOCHTML html>,不清楚请查看参考 ...

  7. windows7内核分析之x86&x64第二章系统调用

    windows7内核分析之x86&x64第二章系统调用 2.1内核与系统调用 上节讲到进入内核五种方式 其中一种就是 系统调用 syscall/sysenter或者int 2e(在 64 位环 ...

  8. linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程

    1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...

  9. Linux内核分析作业7:Linux内核如何装载和启动一个可执行程序

            1.可执行文件的格式 在 Linux 平台下主要有以下三种可执行文件格式: 1.a.out(assembler and link editor output 汇编器和链接编辑器的输出) ...

随机推荐

  1. 亚马逊云服务之CloudFormation

    亚马逊的Web Service其实包含了一套云服务.云服务主要分为三种: IaaS: Infrastructure as a service,基础设施即服务. PaaS: Platform as a ...

  2. 让VS默认以管理员身份运行

    In Windows 8 & 10, you have to right-click devenv.exe and select "Troubleshoot compatibilit ...

  3. MySql查询数据库的大小

    第一步:首先打开Mysql命令行,通过开始菜单-程序-MySql-Command line client,如图1-1所示: 图1-1 第二步:在命令中输入use information_schema ...

  4. paip.文件读写api php java python总结.txt

    paip.文件读写api php java python总结.txt 一.多种方式读文件内容.    1.按字节读取文件内容   以字节为单位读取文件,常用于读二进制文件,如图片.声音.影像等文件. ...

  5. ServiceStack 概念

    目录 ServiceStack 概念 ServiceStack Web Service 创建与调用简单示列 ServiceStack ServiceStack是.Net和Mono的开源框架,相对WCF ...

  6. JavaScript 语句 数组与冒泡排序法

    数组 数组:不管是什么类型,都可以进行存放.存放是有一定顺序的. 顺序:索引号从0开始. 1.需要先对数组进行初始化 var array //数组名称 = new Arrary() //Array 注 ...

  7. 服务器跟VPS有什么区别

    你好. 服务器是独立的真实存在的硬件设备.其实也就是一台高端电脑.他是放在机房运行的.主要为网站以及一些软件应用提供运行平台.而VPS是虚拟服务器.他是利用软件在服务器上虚拟出来的.也就是分配出一部分 ...

  8. C#和.NET Framework的关系

    Year .NET Framework C# 2002 1 1 2003 1.1 1 2005 2 2 泛型 2006 3 2 WPF\WCF\WF 2007 3.5 3 LINQ 2010 4 4 ...

  9. Android gradle问题解决: This app has been built with an incorrect configuration. Please configure your build for VectorDrawableCompat

    1. 问题描述: Android Studio在运行模拟器某些机型或者真机某些机型的时候发生闪退. 错误如下: Java.lang.RuntimeException: Unable to start ...

  10. scikit-learn主要模块和基本使用方法

    从网上看到一篇总结的很不错的sklearn使用文档,备份勿忘. 引言 对于一些开始搞机器学习算法有害怕下手的小朋友,该如何快速入门,这让人挺挣扎的.在从事数据科学的人中,最常用的工具就是R和Pytho ...