参考地址: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 (!proce*tionEndTagForInCaption()) {
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!!!! 完结