参考地址:http://blog.csdn.net/dlmu2001/article/details/6164873 1. 描述Frame类是WebCore内核同应用之间联系的一个重要的类。它有点像设计模式中的Façade,将内核的各个不同的零配件组装在了一起,但又不是Façade,因为用户很多时候还是要直接去操作里面的组件。除了设计上的考虑,Frame还有语法上的意义,它对应于Page里面的帧。 看一下类定义: 1 class Frame : public RefCounted<Frame>, public TiledBackingStoreClient { 2 public: 3 static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); 4 5 void init(); 6 void setView(PassRefPtr<FrameView>); 7 void createView(const IntSize&, const Color&, bool, const IntSize&, bool, 8 ScrollbarMode = ScrollbarAuto, bool horizontalLock = false, 9 ScrollbarMode = ScrollbarAuto, bool verticalLock = false); 10 11 ~Frame(); 12 13 void addDestructionObserver(FrameDestructionObserver*); 14 void removeDestructionObserver(FrameDestructionObserver*); 15 16 void detachFromPage(); 17 void pageDestroyed(); 18 void disconnectOwnerElement(); 19 20 Page* page() const; 21 HTMLFrameOwnerElement* ownerElement() const; 22 23 Document* document() const; 24 FrameView* view() const; 25 26 Editor* editor() const; 27 EventHandler* eventHandler() const; 28 FrameLoader* loader() const; 29 NavigationScheduler* navigationScheduler() const; 30 SelectionController* selection() const; 31 FrameTree* tree() const; 32 AnimationController* animation() const; 33 ScriptController* script(); 34 35 RenderView* contentRenderer() const; // Root of the render tree for the document contained in this frame. 36 RenderPart* ownerRenderer() const; // Renderer for the element that contains this frame. 37 38 void transferChildFrameToNewDocument(); 39 40 // ======== All public functions below this point are candidates to move out of Frame into another class. ======== 41 42 bool isDisconnected() const; 43 void setIsDisconnected(bool); 44 bool excludeFromTextSearch() const; 45 void setExcludeFromTextSearch(bool); 46 47 void injectUserScripts(UserScriptInjectionTime); 48 49 String layerTreeAsText(bool showDebugInfo = false) const; 50 51 // Unlike most accessors in this class, domWindow() always creates a new DOMWindow if m_domWindow is null. 52 // Callers that don't need a new DOMWindow to be created should use existingDOMWindow(). 53 DOMWindow* domWindow() const; 54 DOMWindow* existingDOMWindow() { return m_domWindow.get(); } 55 void setDOMWindow(DOMWindow*); 56 void clearFormerDOMWindow(DOMWindow*); 57 void clearDOMWindow(); 58 59 static Frame* frameForWidget(const Widget*); 60 61 Settings* settings() const; // can be NULL 62 63 enum AdjustViewSizeOrNot { DoNotAdjustViewSize, AdjustViewSize }; 64 void setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot); 65 66 bool inViewSourceMode() const; 67 void setInViewSourceMode(bool = true); 68 69 void keepAlive(); // Used to keep the frame alive when running a script that might destroy it. 70 static void cancelAllKeepAlive(); 71 72 void setDocument(PassRefPtr<Document>); 73 74 void setPageZoomFactor(float factor); 75 float pageZoomFactor() const { return m_pageZoomFactor; } 76 void setTextZoomFactor(float factor); 77 float textZoomFactor() const { return m_textZoomFactor; } 78 void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor); 79 80 void scalePage(float scale, const IntPoint& origin); 81 float pageScaleFactor() const { return m_pageScaleFactor; } 82 83 #if ENABLE(ORIENTATION_EVENTS) 84 // Orientation is the interface orientation in degrees. Some examples are: 85 // 0 is straight up; -90 is when the device is rotated 90 clockwise; 86 // 90 is when rotated counter clockwise. 87 void sendOrientationChangeEvent(int orientation); 88 int orientation() const { return m_orientation; } 89 #endif 90 91 void clearTimers(); 92 static void clearTimers(FrameView*, Document*); 93 94 String documentTypeString() const; 95 96 String displayStringModifiedByEncoding(const String&) const; 97 98 DragImageRef nodeImage(Node*); 99 DragImageRef dragImageForSelection();100 101 VisiblePosition visiblePositionForPoint(const IntPoint& framePoint);102 Document* documentAtPoint(const IntPoint& windowPoint);103 PassRefPtr<Range> rangeForPoint(const IntPoint& framePoint);104 105 String searchForLabelsAboveCell(Regular*, HTMLTableCellElement*, size_t* resultDistanceFromStartOfCell);106 String searchForLabelsBeforeElement(const Vector<String>& labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);107 String matchLabelsAgainstElement(const Vector<String>& labels, Element*);108 109 Color getDocumentBackgroundColor() const;110 111 #if PLATFORM(MAC)112 NSString* searchForLabelsBeforeElement(NSArray* labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);113 NSString* matchLabelsAgainstElement(NSArray* labels, Element*);114 115 NSImage* selectionImage(bool forceBlackText = false) const;116 NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const;117 NSImage* imageFromRect(NSRect) const;118 #endif119 120 #if ENABLE(MEDIA_STREAM)121 MediaStreamFrameController* mediaStreamFrameController() const { return m_mediaStreamFrameController.get(); }122 #endif123 124 // ========125 126 private:127 Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);128 129 void injectUserScriptsForWorld(DOMWrapperWorld*, const UserScriptVector&, UserScriptInjectionTime);130 void lifeSupportTimerFired(Timer<Frame>*);131 132 #if USE(ACCELERATED_COMPOSITING)133 void updateContentsScale(float);134 #endif135 136 HashSet<FrameDestructionObserver*> m_destructionObservers;137 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;171 172 #if ENABLE(TILED_BACKING_STORE)173 // FIXME: The tiled backing store belongs in FrameView, not Frame.174 175 public:176 TiledBackingStore* tiledBackingStore() const { return m_tiledBackingStore.get(); }177 void setTiledBackingStoreEnabled(bool);178 179 private:180 // TiledBackingStoreClient interface181 virtual void tiledBackingStorePaintBegin();182 virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&);183 virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea);184 virtual IntRect tiledBackingStoreContentsRect();185 virtual IntRect tiledBackingStoreVisibleRect();186 virtual Color tiledBackingStoreBackgroundColor() const;187 188 OwnPtr<TiledBackingStore> m_tiledBackingStore;189 #endif190 191 #if ENABLE(MEDIA_STREAM)192 OwnPtr<MediaStreamFrameController> m_mediaStreamFrameController;193 #endif194 } 2. 类结构1,FrameTree对象用来协助管理父帧和子帧的关系,常见的比如 main frame之中有 iframe元素,就会调用 FrameLoaderClientQt::createFrame来产生子帧,产生的子帧会通过appendChild添加到主帧的树状结构中。Frame通过FrameTree对象,可以方便的访问它的父帧,子帧,兄弟帧。 1 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer) 2 { 3 bool allowsScrolling = true; 4 int marginWidth = -1; 5 int marginHeight = -1; 6 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) { 7 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement); 8 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff; 9 marginWidth = o->marginWidth();10 marginHeight = o->marginHeight();11 }12 13 if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {14 FrameLoader::reportLocalLoadFailed(m_frame, url.string());15 return 0;16 }17 18 if (!ownerElement->document()->contentSecurityPolicy()->allowChildFrameFromSource(url))19 return 0;20 21 bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);22 RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);23 24 if (!frame) {25 m_frame->loader()->checkCallImplicitClose();26 return 0;27 }28 29 // All new frames will have m_isComplete set to true at this point due to synchronously loading30 // an empty document in FrameLoader::init(). But many frames will now be starting an31 // asynchronous load of url, so we set m_isComplete to false and then check if the load is32 // actually completed below. (Note that we set m_isComplete to false even for synchronous33 // loads, so that checkCompleted() below won't bail early.)34 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.35 frame->loader()->started();36 37 RenderObject* renderer = ownerElement->renderer();38 FrameView* view = frame->view();39 if (renderer && renderer->isWidget() && view)40 toRenderWidget(renderer)->setWidget(view);41 42 m_frame->loader()->checkCallImplicitClose();43 44 // Some loads are performed synchronously (e.g., about:blank and loads45 // cancelled by returning a null ResourceRequest from requestFromDelegate).46 // In these cases, the synchronous load would have finished47 // before we could connect the signals, so make sure to send the 48 // completed() signal for the child by hand and mark the load as being49 // complete.50 // FIXME: In this case the Frame will have finished loading before 51 // it's being added to the child list. It would be a good idea to52 // create the child first, then invoke the loader separately.53 if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())54 frame->loader()->checkCompleted();55 56 return frame.get();57 } 然后就是创建看createFrame函数 1 PassRefPtr<Frame> FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, 2 const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) 3 { 4 if (!m_webFrame) 5 return 0; 6 7 QWebFrameData frameData(m_frame->page(), m_frame, ownerElement, name); 8 9 if (url.isEmpty())10 frameData.url = blankURL();11 else12 frameData.url = url;13 14 frameData.referrer = referrer;15 frameData.allowsScrolling = allowsScrolling;16 frameData.marginWidth = marginWidth;17 frameData.marginHeight = marginHeight;18 19 QPointer<QWebFrame> webFrame = new QWebFrame(m_webFrame, &frameData);20 // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.21 if (!webFrame->d->frame->page()) {22 frameData.frame.release();23 ASSERT(webFrame.isNull());24 return 0;25 }26 27 emit m_webFrame->page()->frameCreated(webFrame);28 29 // FIXME: Set override encoding if we have one.30 31 m_frame->loader()->loadURLIntoChildFrame(frameData.url, frameData.referrer, frameData.frame.get());32 33 // The frame's onload handler may have removed it from the document.34 if (!frameData.frame->tree()->parent())35 return 0;36 37 return frameData.frame.release();38 } 1 void FrameTree::appendChild(PassRefPtr<Frame> child)2 {3 ASSERT(child->page() == m_thisFrame->page());4 child->tree()->m_parent = m_thisFrame;5 actuallyAppendChild(child); // Note, on return |child| is null.6 } 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 Create1 static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); 2 3 4 5 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) 6 { 7 RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client)); 8 if (!ownerElement) 9 page->setMainFrame(frame);10 return frame.release();11 } 描述: createFrame接口,创建子帧对应的Frame对象,在第一种情况下 HTMLFrameOwnerElement的参数为NULL, 第二种情况传子帧的父元素。在一个tab页内,main frame会重用 调用系列: 1 QwebPage::setView 2 QwebPage::setViewportSize 3 QwebPage::mainFrame 4 QwebPagePrivate::createMainFrame 5 QwebFrameData::QwebFrameData 6 Frame::create 7 8 FrameLoader::finishedLoading 9 ......10 HTMLDocumentParser::append11 ......12 HTMLTreeBuilder::processToken13 ......14 HTMLElementBase::openURL15 SubFrameLoader::requestFrame16 ......17 FrameLoaderClientQt::creatFrame18 QwebFrameData::QwebFrameData19 Frame::create 源码追踪一下(只跟踪源码和颜色标识,不解释): 第一种情况下: 1, 1 void QWebPage::setView(QWidget* view) 2 { 3 if (this->view() == view) 4 return; 5 6 d->view = view; 7 setViewportSize(view ? view->size() : QSize(0, 0)); 8 9 // If we have no client, we install a special client delegating10 // the responsibility to the QWidget. This is the code path11 // handling a.o. the "legacy" QWebView.12 //13 // If such a special delegate already exist, we substitute the view.14 15 if (d->client) {16 if (d->client->isQWidgetClient())17 static_cast<PageClientQWidget*>(d->client.get())->view = view;18 return;19 }20 21 if (view)22 d->client = new PageClientQWidget(view, this);23 } 2, 1 void QWebPage::setViewportSize(const QSize &size) const 2 { 3 d->viewportSize = size; 4 5 QWebFrame *frame = mainFrame(); 6 if (frame->d->frame && frame->d->frame->view()) { 7 WebCore::FrameView* view = frame->d->frame->view(); 8 view->resize(size); 9 view->adjustViewSize();10 }11 } 3, 1 QWebFrame *QWebPage::mainFrame() const2 {3 d->createMainFrame();4 return d->mainFrame;5 } 4, 1 void QWebPagePrivate::createMainFrame()2 {3 if (!mainFrame) {4 QWebFrameData frameData(page);5 mainFrame = new QWebFrame(q, &frameData);6 7 emit q->frameCreated(mainFrame);8 }9 } 5, 1 QWebFrameData(WebCore::Page*, WebCore::Frame* parentFrame = 0,2 WebCore::HTMLFrameOwnerElement* = 0,3 const WTF::String& frameName = WTF::String()); 6, 1 QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame, 2 WebCore::HTMLFrameOwnerElement* ownerFrameElement, 3 const WTF::String& frameName) 4 : name(frameName) 5 , ownerElement(ownerFrameElement) 6 , page(parentPage) 7 , allowsScrolling(true) 8 , marginWidth(0) 9 , marginHeight(0)10 {11 frameLoaderClient = new FrameLoaderClientQt();12 frame = Frame::create(page, ownerElement, frameLoaderClient);13 14 // FIXME: All of the below should probably be moved over into WebCore15 frame->tree()->setName(name);16 if (parentFrame)17 parentFrame->tree()->appendChild(frame);18 } 第二种情况下: 1,FrameLoader::finishedLoading() 1 void FrameLoader::finishedLoading() 2 { 3 // Retain because the stop may release the last reference to it. 4 RefPtr<Frame> protect(m_frame); 5 6 RefPtr<DocumentLoader> dl = activeDocumentLoader(); 7 dl->finishedLoading(); 8 if (!dl->mainDocumentError().isNull() || !dl->frameLoader()) 9 return;10 dl->setPrimaryLoadComplete(true);11 m_client->dispatchDidLoadMainResource(dl.get());12 checkLoadComplete();13 } 2,DocumentLoader::finishedLoading() 1 void DocumentLoader::finishedLoading()2 {3 m_gotFirstByte = true; 4 commitIfReady();5 if (FrameLoader* loader = frameLoader()) {6 loader->finishedLoadingDocument(this);7 m_writer.end();8 }9 } 3,DocumentWriter::end() 1 void DocumentWriter::end()2 {3 m_frame->loader()->didEndDocument();4 endIfNotLoadingMainResource();5 } 4, DocumentWriter::endIfNotLoadingMainResource() 1 void DocumentWriter::endIfNotLoadingMainResource() 2 { 3 if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document()) 4 return; 5 6 // http://bugs./show_bug.cgi?id=10854 7 // The frame's last ref may be removed and it can be deleted by checkCompleted(), 8 // so we'll add a protective refcount 9 RefPtr<Frame> protector(m_frame);10 11 // make sure nothing's left in there12 addData(0, 0, true);13 m_frame->document()->finishParsing();14 } 5,DocumentWriter::addData(const char* str, int len, bool flush) 1 void DocumentWriter::addData(const char* str, int len, bool flush)2 {3 if (len == -1)4 len = strlen(str);5 6 DocumentParser* parser = m_frame->document()->parser();7 if (parser)8 parser->appendBytes(this, str, len, flush);9 } 6,DecodedDataDocumentParser::appendBytes(DocumentWriter* writer , const char* data, int length, bool shouldFlush) 1 void DecodedDataDocumentParser::appendBytes(DocumentWriter* writer , const char* data, int length, bool shouldFlush) 2 { 3 if (!length && !shouldFlush) 4 return; 5 6 TextResourceDecoder* decoder = writer->createDecoderIfNeeded(); 7 String decoded = decoder->decode(data, length); 8 if (shouldFlush) 9 decoded += decoder->flush();10 if (decoded.isEmpty())11 return;12 13 writer->reportDataReceived();14 15 append(decoded);16 } 7,HTMLDocumentParser::append(const SegmentedString& source) 1 void HTMLDocumentParser::append(const SegmentedString& source) 2 { 3 if (isStopped()) 4 return; 5 6 // pumpTokenizer can cause this parser to be detached from the Document, 7 // but we need to ensure it isn't deleted yet. 8 RefPtr<HTMLDocumentParser> protect(this); 9 10 if (m_preloadScanner) {11 if (m_input.current().isEmpty() && !isWaitingForScripts()) {12 // We have parsed until the end of the current input and so are now moving ahead of the preload scanner.13 // Clear the scanner so we know to scan starting from the current input point if we block again.14 m_preloadScanner.clear();15 } else {16 m_preloadScanner->appendToEnd(source);17 if (isWaitingForScripts())18 m_preloadScanner->scan();19 }20 }21 22 m_input.appendToEnd(source);23 24 if (inPumpSession()) {25 // We've gotten data off the network in a nested write.26 // We don't want to consume any more of the input stream now. Do27 // not worry. We'll consume this data in a less-nested write().28 return;29 }30 31 pumpTokenizerIfPossible(AllowYield);32 33 endIfDelayed();34 } 8,HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode) 1 void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode) 2 { 3 if (isStopped() || m_treeBuilder->isPaused()) 4 return; 5 6 // Once a resume is scheduled, HTMLParserScheduler controls when we next pump. 7 if (isScheduledForResume()) { 8 ASSERT(mode == AllowYield); 9 return;10 }11 12 pumpTokenizer(mode);13 } 9,HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) 1 void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) 2 { 3 ASSERT(!isStopped()); 4 ASSERT(!isScheduledForResume()); 5 // ASSERT that this object is both attached to the Document and protected. 6 ASSERT(refCount() >= 2); 7 8 PumpSession session(m_pumpSessionNestingLevel); 9 10 // We tell the InspectorInstrumentation about every pump, even if we11 // end up pumping nothing. It can filter out empty pumps itself.12 // FIXME: m_input.current().length() is only accurate if we13 // end up parsing the whole buffer in this pump. We should pass how14 // much we parsed as part of didWriteHTML instead of willWriteHTML.15 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().length(), m_tokenizer->lineNumber());16 17 while (canTakeNextToken(mode, session) && !session.needsYield) {18 if (!isParsingFragment())19 m_sourceTracker.start(m_input, m_token);20 21 if (!m_tokenizer->nextToken(m_input.current(), m_token))22 break;23 24 if (!isParsingFragment()) {25 m_sourceTracker.end(m_input, m_token);26 27 // We do not XSS filter innerHTML, which means we (intentionally) fail28 // http/tests/security/xssAuditor/dom-write-innerHTML.html29 m_xssFilter.filterToken(m_token);30 }31 32 m_treeBuilder->constructTreeFromToken(m_token);33 ASSERT(m_token.isUninitialized());34 }35 36 // Ensure we haven't been totally deref'ed after pumping. Any caller of this37 // function should be holding a RefPtr to this to ensure we weren't deleted.38 ASSERT(refCount() >= 1);39 40 if (isStopped())41 return;42 43 if (session.needsYield)44 m_parserScheduler->scheduleForResume();45 46 if (isWaitingForScripts()) {47 ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);48 if (!m_preloadScanner) {49 m_preloadScanner = adoptPtr(new HTMLPreloadScanner(document()));50 m_preloadScanner->appendToEnd(m_input.current());51 }52 m_preloadScanner->scan();53 }54 55 InspectorInstrumentation::didWriteHTML(cookie, m_tokenizer->lineNumber());56 } 10,HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken) 1 void HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken) 2 { 3 AtomicHTMLToken token(rawToken); 4 5 // We clear the rawToken in case constructTreeFromAtomicToken 6 // synchronously re-enters the parser. We don't clear the token immedately 7 // for Character tokens because the AtomicHTMLToken avoids copying the 8 // characters by keeping a pointer to the underlying buffer in the 9 // HTMLToken. Fortuantely, Character tokens can't cause use to re-enter10 // the parser.11 //12 // FIXME: Top clearing the rawToken once we start running the parser off13 // the main thread or once we stop allowing synchronous JavaScript14 // execution from parseMappedAttribute.15 if (rawToken.type() != HTMLToken::Character)16 rawToken.clear();17 18 constructTreeFromAtomicToken(token);19 20 if (!rawToken.isUninitialized()) {21 ASSERT(rawToken.type() == HTMLToken::Character);22 rawToken.clear();23 }24 } 11,HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token) 1 void HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token) 2 { 3 processToken(token); 4 5 // Swallowing U+0000 characters isn't in the HTML5 spec, but turning all 6 // the U+0000 characters into replacement characters has compatibility 7 // problems. 8 m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || m_insertionMode == InForeignContentMode); 9 m_parser->tokenizer()->setShouldAllowCDATA(m_insertionMode == InForeignContentMode && !isInHTMLNamespace(m_tree.currentNode()));10 } 12,HTMLTreeBuilder::processToken(AtomicHTMLToken& token) 1 void HTMLTreeBuilder::processToken(AtomicHTMLToken& token) 2 { 3 switch (token.type()) { 4 case HTMLToken::Uninitialized: 5 ASSERT_NOT_REACHED(); 6 break; 7 case HTMLToken::DOCTYPE: 8 processDoctypeToken(token); 9 break;10 case HTMLToken::StartTag:11 processStartTag(token);12 break;13 case HTMLToken::EndTag:14 processEndTag(token);15 break;16 case HTMLToken::Comment:17 processComment(token);18 return;19 case HTMLToken::Character:20 processCharacter(token);21 break;22 case HTMLToken::EndOfFile:23 processEndOfFile(token);24 break;25 }26 } 13,HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) 1 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) 2 { 3 ASSERT(token.type() == HTMLToken::StartTag); 4 switch (insertionMode()) { 5 case InitialMode: 6 ASSERT(insertionMode() == InitialMode); 7 defaultForInitial(); 8 // Fall through. 9 case BeforeHTMLMode: 10 ASSERT(insertionMode() == BeforeHTMLMode); 11 if (token.name() == htmlTag) { 12 m_tree.insertHTMLHtmlStartTagBeforeHTML(token); 13 setInsertionMode(BeforeHeadMode); 14 return; 15 } 16 defaultForBeforeHTML(); 17 // Fall through. 18 case BeforeHeadMode: 19 ASSERT(insertionMode() == BeforeHeadMode); 20 if (token.name() == htmlTag) { 21 m_tree.insertHTMLHtmlStartTagInBody(token); 22 return; 23 } 24 if (token.name() == headTag) { 25 m_tree.insertHTMLHeadElement(token); 26 setInsertionMode(InHeadMode); 27 return; 28 } 29 defaultForBeforeHead(); 30 // Fall through. 31 case InHeadMode: 32 ASSERT(insertionMode() == InHeadMode); 33 if (processStartTagForInHead(token)) 34 return; 35 defaultForInHead(); 36 // Fall through. 37 case AfterHeadMode: 38 ASSERT(insertionMode() == AfterHeadMode); 39 if (token.name() == htmlTag) { 40 m_tree.insertHTMLHtmlStartTagInBody(token); 41 return; 42 } 43 if (token.name() == bodyTag) { 44 m_framesetOk = false; 45 m_tree.insertHTMLBodyElement(token); 46 setInsertionMode(InBodyMode); 47 return; 48 } 49 if (token.name() == framesetTag) { 50 m_tree.insertHTMLElement(token); 51 setInsertionMode(InFramesetMode); 52 return; 53 } 54 if (token.name() == baseTag 55 || token.name() == basefontTag 56 || token.name() == bgsoundTag 57 || token.name() == linkTag 58 || token.name() == metaTag 59 || token.name() == noframesTag 60 || token.name() == scriptTag 61 || token.name() == styleTag 62 || token.name() == titleTag) { 63 parseError(token); 64 ASSERT(m_tree.head()); 65 m_tree.openElements()->pushHTMLHeadElement(m_tree.head()); 66 processStartTagForInHead(token); 67 m_tree.openElements()->removeHTMLHeadElement(m_tree.head()); 68 return; 69 } 70 if (token.name() == headTag) { 71 parseError(token); 72 return; 73 } 74 defaultForAfterHead(); 75 // Fall through 76 case InBodyMode: 77 ASSERT(insertionMode() == InBodyMode); 78 processStartTagForInBody(token); 79 break; 80 case InTableMode: 81 ASSERT(insertionMode() == InTableMode); 82 processStartTagForInTable(token); 83 break; 84 case InCaptionMode: 85 ASSERT(insertionMode() == InCaptionMode); 86 if (isCaptionColOrColgroupTag(token.name()) 87 || isTableBodyContextTag(token.name()) 88 || isTableCellContextTag(token.name()) 89 || token.name() == trTag) { 90 parseError(token); 91 if (!processCaptionEndTagForInCaption()) { 92 ASSERT(isParsingFragment()); 93 return; 94 } 95 reprocessStartTag(token); 96 return; 97 } 98 processStartTagForInBody(token); 99 break;100 case InColumnGroupMode:101 ASSERT(insertionMode() == InColumnGroupMode);102 if (token.name() == htmlTag) {103 m_tree.insertHTMLHtmlStartTagInBody(token);104 return;105 }106 if (token.name() == colTag) {107 m_tree.insertSelfClosingHTMLElement(token);108 return;109 }110 if (!processColgroupEndTagForInColumnGroup()) {111 ASSERT(isParsingFragment());112 return;113 }114 reprocessStartTag(token);115 break;116 case InTableBodyMode:117 ASSERT(insertionMode() == InTableBodyMode);118 if (token.name() == trTag) {119 m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop?120 m_tree.insertHTMLElement(token);121 setInsertionMode(InRowMode);122 return;123 }124 if (isTableCellContextTag(token.name())) {125 parseError(token);126 processFakeStartTag(trTag);127 ASSERT(insertionMode() == InRowMode);128 reprocessStartTag(token);129 return;130 }131 if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) {132 // FIXME: This is slow.133 if (!m_tree.openElements()->inTableScope(tbodyTag.localName()) && !m_tree.openElements()->inTableScope(theadTag.localName()) && !m_tree.openElements()->inTableScope(tfootTag.localName())) {134 ASSERT(isParsingFragment());135 parseError(token);136 return;137 }138 m_tree.openElements()->popUntilTableBodyScopeMarker();139 ASSERT(isTableBodyContextTag(m_tree.currentElement()->localName()));140 processFakeEndTag(m_tree.currentElement()->tagQName());141 reprocessStartTag(token);142 return;143 }144 processStartTagForInTable(token);145 break;146 case InRowMode:147 ASSERT(insertionMode() == InRowMode);148 if (isTableCellContextTag(token.name())) {149 m_tree.openElements()->popUntilTableRowScopeMarker();150 m_tree.insertHTMLElement(token);151 setInsertionMode(InCellMode);152 m_tree.activeFormattingElements()->appendMarker();153 return;154 }155 if (token.name() == trTag156 || isCaptionColOrColgroupTag(token.name())157 || isTableBodyContextTag(token.name())) {158 if (!processTrEndTagForInRow()) {159 ASSERT(isParsingFragment());160 return;161 }162 ASSERT(insertionMode() == InTableBodyMode);163 reprocessStartTag(token);164 return;165 }166 processStartTagForInTable(token);167 break;168 case InCellMode:169 ASSERT(insertionMode() == InCellMode);170 if (isCaptionColOrColgroupTag(token.name())171 || isTableCellContextTag(token.name())172 || token.name() == trTag173 || isTableBodyContextTag(token.name())) {174 // FIXME: This could be more efficient.175 if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) {176 ASSERT(isParsingFragment());177 parseError(token);178 return;179 }180 closeTheCell();181 reprocessStartTag(token);182 return;183 }184 processStartTagForInBody(token);185 break;186 case AfterBodyMode:187 case AfterAfterBodyMode:188 ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);189 if (token.name() == htmlTag) {190 m_tree.insertHTMLHtmlStartTagInBody(token);191 return;192 }193 setInsertionMode(InBodyMode);194 reprocessStartTag(token);195 break;196 case InHeadNoscriptMode:197 ASSERT(insertionMode() == InHeadNoscriptMode);198 if (token.name() == htmlTag) {199 m_tree.insertHTMLHtmlStartTagInBody(token);200 return;201 }202 if (token.name() == basefontTag203 || token.name() == bgsoundTag204 || token.name() == linkTag205 || token.name() == metaTag206 || token.name() == noframesTag207 || token.name() == styleTag) {208 bool didProcess = processStartTagForInHead(token);209 ASSERT_UNUSED(didProcess, didProcess);210 return;211 }212 if (token.name() == htmlTag || token.name() == noscriptTag) {213 parseError(token);214 return;215 }216 defaultForInHeadNoscript();217 processToken(token);218 break;219 case InFramesetMode:220 ASSERT(insertionMode() == InFramesetMode);221 if (token.name() == htmlTag) {222 m_tree.insertHTMLHtmlStartTagInBody(token);223 return;224 }225 if (token.name() == framesetTag) {226 m_tree.insertHTMLElement(token);227 return;228 }229 if (token.name() == frameTag) {230 m_tree.insertSelfClosingHTMLElement(token);231 return;232 }233 if (token.name() == noframesTag) {234 processStartTagForInHead(token);235 return;236 }237 parseError(token);238 break;239 case AfterFramesetMode:240 case AfterAfterFramesetMode:241 ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);242 if (token.name() == htmlTag) {243 m_tree.insertHTMLHtmlStartTagInBody(token);244 return;245 }246 if (token.name() == noframesTag) {247 processStartTagForInHead(token);248 return;249 }250 parseError(token);251 break;252 case InSelectInTableMode:253 ASSERT(insertionMode() == InSelectInTableMode);254 if (token.name() == captionTag255 || token.name() == tableTag256 || isTableBodyContextTag(token.name())257 || token.name() == trTag258 || isTableCellContextTag(token.name())) {259 parseError(token);260 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());261 processEndTag(endSelect);262 reprocessStartTag(token);263 return;264 }265 // Fall through266 case InSelectMode:267 ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);268 if (token.name() == htmlTag) {269 m_tree.insertHTMLHtmlStartTagInBody(token);270 return;271 }272 if (token.name() == optionTag) {273 if (m_tree.currentNode()->hasTagName(optionTag)) {274 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());275 processEndTag(endOption);276 }277 m_tree.insertHTMLElement(token);278 return;279 }280 if (token.name() == optgroupTag) {281 if (m_tree.currentNode()->hasTagName(optionTag)) {282 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());283 processEndTag(endOption);284 }285 if (m_tree.currentNode()->hasTagName(optgroupTag)) {286 AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());287 processEndTag(endOptgroup);288 }289 m_tree.insertHTMLElement(token);290 return;291 }292 if (token.name() == selectTag) {293 parseError(token);294 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());295 processEndTag(endSelect);296 return;297 }298 if (token.name() == inputTag299 || token.name() == keygenTag300 || token.name() == textareaTag) {301 parseError(token);302 if (!m_tree.openElements()->inSelectScope(selectTag)) {303 ASSERT(isParsingFragment());304 return;305 }306 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());307 processEndTag(endSelect);308 reprocessStartTag(token);309 return;310 }311 if (token.name() == scriptTag) {312 bool didProcess = processStartTagForInHead(token);313 ASSERT_UNUSED(didProcess, didProcess);314 return;315 }316 break;317 case InTableTextMode:318 defaultForInTableText();319 processStartTag(token);320 break;321 case InForeignContentMode: {322 if (shouldProcessForeignContentUsingInBodyInsertionMode(token, m_tree.currentNode())) {323 processForeignContentUsingInBodyModeAndResetMode(token);324 return;325 }326 if (token.name() == bTag327 || token.name() == bigTag328 || token.name() == blockquoteTag329 || token.name() == bodyTag330 || token.name() == brTag331 || token.name() == centerTag332 || token.name() == codeTag333 || token.name() == ddTag334 || token.name() == divTag335 || token.name() == dlTag336 || token.name() == dtTag337 || token.name() == emTag338 || token.name() == embedTag339 || isNumberedHeaderTag(token.name())340 || token.name() == headTag341 || token.name() == hrTag342 || token.name() == iTag343 || token.name() == imgTag344 || token.name() == liTag345 || token.name() == listingTag346 || token.name() == menuTag347 || token.name() == metaTag348 || token.name() == nobrTag349 || token.name() == olTag350 || token.name() == pTag351 || token.name() == preTag352 || token.name() == rubyTag353 || token.name() == sTag354 || token.name() == smallTag355 || token.name() == spanTag356 || token.name() == strongTag357 || token.name() == strikeTag358 || token.name() == subTag359 || token.name() == supTag360 || token.name() == tableTag361 || token.name() == ttTag362 || token.name() == uTag363 || token.name() == ulTag364 || token.name() == varTag365 || (token.name() == fontTag && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr)))) {366 parseError(token);367 m_tree.openElements()->popUntilForeignContentScopeMarker();368 resetInsertionModeAppropriately();369 reprocessStartTag(token);370 return;371 }372 const AtomicString& currentNamespace = m_tree.currentElement()->namespaceURI();373 if (currentNamespace == MathMLNames::mathmlNamespaceURI)374 adjustMathMLAttributes(token);375 if (currentNamespace == SVGNames::svgNamespaceURI) {376 adjustSVGTagNameCase(token);377 adjustSVGAttributes(token);378 }379 adjustForeignAttributes(token);380 m_tree.insertForeignElement(token, currentNamespace);381 break;382 }383 case TextMode:384 ASSERT_NOT_REACHED();385 break;386 }387 } 14,HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken& token) 1 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken& token)2 {3 m_openElements.push(attachToCurrent(createHTMLElement(token)));4 } 15,HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child) 1 PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)2 {3 return attach(currentNode(), child);4 } 16,HTMLConstructionSite::attach(ContainerNode* rawParent, PassRefPtr<ChildType> prpChild) 1 template<typename ChildType> 2 PassRefPtr<ChildType> HTMLConstructionSite::attach(ContainerNode* rawParent, PassRefPtr<ChildType> prpChild) 3 { 4 RefPtr<ChildType> child = prpChild; 5 RefPtr<ContainerNode> parent = rawParent; 6 7 // FIXME: It's confusing that HTMLConstructionSite::attach does the magic 8 // redirection to the foster parent but HTMLConstructionSite::attachAtSite 9 // doesn't. It feels like we're missing a concept somehow.10 if (shouldFosterParent()) {11 fosterParent(child.get());12 ASSERT(child->attached() || !child->parentNode() || !child->parentNode()->attached());13 return child.release();14 }15 16 parent->parserAddChild(child);17 18 // An event handler (DOM Mutation, beforeload, et al.) could have removed19 // the child, in which case we shouldn't try attaching it.20 if (!child->parentNode())21 return child.release();22 23 if (parent->attached() && !child->attached())24 child->attach();25 return child.release();26 } 17,ContainerNode::parserAddChild(PassRefPtr<Node> newChild) 1 void ContainerNode::parserAddChild(PassRefPtr<Node> newChild) 2 { 3 ASSERT(newChild); 4 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events). 5 6 #if ENABLE(INSPECTOR) 7 InspectorInstrumentation::willInsertDOMNode(document(), newChild.get(), this); 8 #endif 9 10 forbidEventDispatch();11 Node* last = m_lastChild;12 // FIXME: This method should take a PassRefPtr.13 appendChildToContainer<Node, ContainerNode>(newChild.get(), this);14 newChild->setTreeScopeRecursively(treeScope());15 16 allowEventDispatch();17 18 // FIXME: Why doesn't this use notifyChildInserted(newChild) instead?19 document()->incDOMTreeVersion();20 if (inDocument())21 newChild->insertedIntoDocument();22 childrenChanged(true, last, 0, 1);23 } 18,ContainerNode::insertedIntoDocument() 1 void ContainerNode::insertedIntoDocument() 2 { 3 RefPtr<Node> protect(this); 4 5 Node::insertedIntoDocument(); 6 insertedIntoTree(false); 7 8 for (RefPtr<Node> child = m_firstChild; child; child = child->nextSibling()) { 9 // Guard against mutation during re-parenting.10 if (!inDocument()) // Check for self being removed from document while reparenting.11 break;12 if (child->parentNode() != this) // Check for child being removed from subtree while reparenting.13 break;14 child->insertedIntoDocument();15 }16 } 19,HTMLFrameElementBase::insertedIntoDocument() 1 void HTMLFrameElementBase::insertedIntoDocument() 2 { 3 HTMLFrameOwnerElement::insertedIntoDocument(); 4 5 if (m_remainsAliveOnRemovalFromTree) { 6 updateOnReparenting(); 7 setRemainsAliveOnRemovalFromTree(false); 8 return; 9 }10 // DocumentFragments don't kick of any loads.11 if (!document()->frame())12 return;13 14 // Loads may cause synchronous javascript execution (e.g. beforeload or15 // src=javascript), which could try to access the renderer before the normal16 // parser machinery would call lazyAttach() and set us as needing style17 // resolve. Any code which expects this to be attached will resolve style18 // before using renderer(), so this will make sure we attach in time.19 // FIXME: Normally lazyAttach marks the renderer as attached(), but we don't20 // want to do that here, as as callers expect to call attach() right after21 // this and attach() will ASSERT(!attached())22 ASSERT(!renderer()); // This recalc is unecessary if we already have a renderer.23 lazyAttach(DoNotSetAttached);24 setNameAndOpenURL();25 } 20,HTMLFrameElementBase::setNameAndOpenURL() 1 void HTMLFrameElementBase::setNameAndOpenURL()2 {3 m_frameName = getAttribute(nameAttr);4 if (m_frameName.isNull())5 m_frameName = getIdAttribute();6 openURL();7 } 21,HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList) 1 void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList) 2 { 3 if (!isURLAllowed()) 4 return; 5 6 if (m_URL.isEmpty()) 7 m_URL = blankURL().string(); 8 9 Frame* parentFrame = document()->frame();10 if (!parentFrame)11 return;12 13 parentFrame->loader()->subframeLoader()->requestFrame(this, m_URL, m_frameName, lockHistory, lockBackForwardList);14 if (contentFrame())15 contentFrame()->setInViewSourceMode(viewSourceMode());16 } 22,SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList) 1 bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList) 2 { 3 // Support for <frame src="javascript:string"> 4 KURL scriptURL; 5 KURL url; 6 if (protocolIsJavaScript(urlString)) { 7 scriptURL = completeURL(urlString); // completeURL() encodes the URL. 8 url = blankURL(); 9 } else10 url = completeURL(urlString);11 12 Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);13 if (!frame)14 return false;15 16 if (!scriptURL.isEmpty())17 frame->script()->executeIfJavaScriptURL(scriptURL);18 19 return true;20 } 23,SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList) 1 Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)2 {3 Frame* frame = ownerElement->contentFrame();4 if (frame)5 frame->navigationScheduler()->scheduleLocationChange(m_frame->document()->securityOrigin(), url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);6 else7 frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());8 return frame;9 } 24,SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer) 1 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer) 2 { 3 bool allowsScrolling = true; 4 int marginWidth = -1; 5 int marginHeight = -1; 6 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) { 7 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement); 8 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff; 9 marginWidth = o->marginWidth();10 marginHeight = o->marginHeight();11 }12 13 if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {14 FrameLoader::reportLocalLoadFailed(m_frame, url.string());15 return 0;16 }17 18 if (!ownerElement->document()->contentSecurityPolicy()->allowChildFrameFromSource(url))19 return 0;20 21 bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);22 RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);23 24 if (!frame) {25 m_frame->loader()->checkCallImplicitClose();26 return 0;27 }28 29 // All new frames will have m_isComplete set to true at this point due to synchronously loading30 // an empty document in FrameLoader::init(). But many frames will now be starting an31 // asynchronous load of url, so we set m_isComplete to false and then check if the load is32 // actually completed below. (Note that we set m_isComplete to false even for synchronous33 // loads, so that checkCompleted() below won't bail early.)34 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.35 frame->loader()->started();36 37 RenderObject* renderer = ownerElement->renderer();38 FrameView* view = frame->view();39 if (renderer && renderer->isWidget() && view)40 toRenderWidget(renderer)->setWidget(view);41 42 m_frame->loader()->checkCallImplicitClose();43 44 // Some loads are performed synchronously (e.g., about:blank and loads45 // cancelled by returning a null ResourceRequest from requestFromDelegate).46 // In these cases, the synchronous load would have finished47 // before we could connect the signals, so make sure to send the 48 // completed() signal for the child by hand and mark the load as being49 // complete.50 // FIXME: In this case the Frame will have finished loading before 51 // it's being added to the child list. It would be a good idea to52 // create the child first, then invoke the loader separately.53 if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())54 frame->loader()->checkCompleted();55 56 return frame.get();57 } 25,FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) 1 PassRefPtr<Frame> FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, 2 const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) 3 { 4 if (!m_webFrame) 5 return 0; 6 7 QWebFrameData frameData(m_frame->page(), m_frame, ownerElement, name); 8 9 if (url.isEmpty())10 frameData.url = blankURL();11 else12 frameData.url = url;13 14 frameData.referrer = referrer;15 frameData.allowsScrolling = allowsScrolling;16 frameData.marginWidth = marginWidth;17 frameData.marginHeight = marginHeight;18 19 QPointer<QWebFrame> webFrame = new QWebFrame(m_webFrame, &frameData);20 // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.21 if (!webFrame->d->frame->page()) {22 frameData.frame.release();23 ASSERT(webFrame.isNull());24 return 0;25 }26 27 emit m_webFrame->page()->frameCreated(webFrame);28 29 // FIXME: Set override encoding if we have one.30 31 m_frame->loader()->loadURLIntoChildFrame(frameData.url, frameData.referrer, frameData.frame.get());32 33 // The frame's onload handler may have removed it from the document.34 if (!frameData.frame->tree()->parent())35 return 0;36 37 return frameData.frame.release();38 } 26,QWebFrameData::QWebFrameData(... ) 1 QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame, 2 WebCore::HTMLFrameOwnerElement* ownerFrameElement, 3 const WTF::String& frameName) 4 : name(frameName) 5 , ownerElement(ownerFrameElement) 6 , page(parentPage) 7 , allowsScrolling(true) 8 , marginWidth(0) 9 , marginHeight(0)10 {11 frameLoaderClient = new FrameLoaderClientQt();12 frame = Frame::create(page, ownerElement, frameLoaderClient);13 14 // FIXME: All of the below should probably be moved over into WebCore15 frame->tree()->setName(name);16 if (parentFrame)17 parentFrame->tree()->appendChild(frame);18 } OK,代码量太庞大了,至此,代码跟踪完成!!! 3.2 createView 1 void createView(const IntSize&, const Color&, bool, const IntSize&, bool,2 ScrollbarMode = ScrollbarAuto, bool horizontalLock = false,3 ScrollbarMode = ScrollbarAuto, bool verticalLock = false); 描述: 实现: 1 void Frame::setView(PassRefPtr<FrameView> view) 2 { 3 // We the custom scroll bars as early as possible to prevent m_doc->detach() 4 // from messing with the view such that its scroll bars won't be torn down. 5 // FIXME: We should revisit this. 6 if (m_view) 7 m_view->detachCustomScrollbars(); 8 9 // Detach the document now, so any onUnload handlers get run - if10 // we wait until the view is destroyed, then things won't be11 // hooked up enough for some JavaScript calls to work.12 if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {13 // FIXME: We don't call willRemove here. Why is that OK?14 m_doc->detach();15 }16 17 if (m_view)18 m_view->unscheduleRelayout();19 20 eventHandler()->clear();21 22 m_view = view;23 24 // Only one form submission is allowed per view of a part.25 // Since this part may be getting reused as a result of being26 // pulled from the back/forward cache, reset this flag.27 loader()->resetMultipleFormSubmissionProtection();28 29 #if ENABLE(TILED_BACKING_STORE)30 if (m_view && tiledBackingStore())31 m_view->setPaintsEntireContents(true);32 #endif33 } 函数调用系列: 1 FrameLoader::commitProvisionalLoad2 FrameLoader::transitionToCommitted3 FrameLoaderClientQt::transitionToCommittedForNewPage4 Frame::createView 跟踪一下代码(同上) 1 void QWebView::load(const QUrl &url)2 {3 page()->mainFrame()->load(url);4 } 2,QWebFrame::load(const QNetworkRequest &req,QNetworkAccessManager::Operation operation,const QByteArray &body) 1 void QWebFrame::load(const QNetworkRequest &req, 2 QNetworkAccessManager::Operation operation, 3 const QByteArray &body) 4 { 5 if (d->parentFrame()) 6 d->page->d->insideOpenCall = true; 7 8 QUrl url = ensureAbsoluteUrl(req.url()); 9 10 WebCore::ResourceRequest request(url);11 12 switch (operation) {13 case QNetworkAccessManager::HeadOperation:14 request.setHTTPMethod("HEAD");15 break;16 case QNetworkAccessManager::GetOperation:17 request.setHTTPMethod("GET");18 break;19 case QNetworkAccessManager::PutOperation:20 request.setHTTPMethod("PUT");21 break;22 case QNetworkAccessManager::PostOperation:23 request.setHTTPMethod("POST");24 break;25 case QNetworkAccessManager::DeleteOperation:26 request.setHTTPMethod("DELETE");27 break;28 case QNetworkAccessManager::CustomOperation:29 request.setHTTPMethod(req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray().constData());30 break;31 case QNetworkAccessManager::UnknownOperation:32 // eh?33 break;34 }35 36 QVariant cacheLoad = req.attribute(QNetworkRequest::CacheLoadControlAttribute);37 if (cacheLoad.isValid()) {38 bool ok;39 uint cacheLoadValue = cacheLoad.toUInt(&ok);40 if (ok)41 request.setCachePolicy(cacheLoadControlToCachePolicy(cacheLoadValue));42 }43 44 QList<QByteArray> httpHeaders = req.rawHeaderList();45 for (int i = 0; i < httpHeaders.size(); ++i) {46 const QByteArray &headerName = httpHeaders.at(i);47 request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));48 }49 50 if (!body.isEmpty())51 request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));52 53 d->frame->loader()->load(request, false);54 55 if (d->parentFrame())56 d->page->d->insideOpenCall = false;57 } 3, FrameLoader::load(const ResourceRequest& request, bool lockHistory) 1 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)2 {3 load(request, SubstituteData(), lockHistory);4 } 4,FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory) 1 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory) 2 { 3 if (m_inStopAllLoaders) 4 return; 5 6 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted. 7 m_loadType = FrameLoadTypeStandard; 8 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData); 9 if (lockHistory && m_documentLoader)10 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());11 load(loader.get());12 } 5,FrameLoader::load(DocumentLoader* newDocumentLoader) 1 void FrameLoader::load(DocumentLoader* newDocumentLoader) 2 { 3 ResourceRequest& r = newDocumentLoader->request(); 4 addExtraFieldsToMainResourceRequest(r); 5 FrameLoadType type; 6 7 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) { 8 r.setCachePolicy(ReloadIgnoringCacheData); 9 type = FrameLoadTypeSame;10 } else11 type = FrameLoadTypeStandard;12 13 if (m_documentLoader)14 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());15 16 // When we loading alternate content for an unreachable URL that we're17 // visiting in the history list, we treat it as a reload so the history list 18 // is appropriately maintained.19 //20 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...21 // shouldn't a more explicit type of reload be defined, that means roughly 22 // "load without affecting history" ? 23 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {24 // shouldReloadToHandleUnreachableURL() returns true only when the original load type is back-forward.25 // In this case we should save the document state now. Otherwise the state can be lost because load type is26 // changed and updateForBackForwardNavigation() will not be called when loading is committed.27 history()->saveDocumentAndScrollState();28 29 ASSERT(type == FrameLoadTypeStandard);30 type = FrameLoadTypeReload;31 }32 33 loadWithDocumentLoader(newDocumentLoader, type, 0);34 } 6,FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState) 1 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState) 2 { 3 // Retain because dispatchBeforeLoadEvent may release the last reference to it. 4 RefPtr<Frame> protect(m_frame); 5 6 ASSERT(m_client->hasWebView()); 7 8 // Unfortunately the view must be non-nil, this is ultimately due 9 // to parser requiring a FrameView. We should fix this dependency.10 11 ASSERT(m_frame->view());12 13 if (m_pageDismissalEventBeingDispatched)14 return;15 16 if (m_frame->document())17 m_previousUrl = m_frame->document()->url();18 19 policyChecker()->setLoadType(type);20 RefPtr<FormState> formState = prpFormState;21 bool isFormSubmission = formState;22 23 const KURL& newURL = loader->request().url();24 const String& httpMethod = loader->request().httpMethod();25 26 if (shouldScrollToAnchor(isFormSubmission, httpMethod, policyChecker()->loadType(), newURL)) {27 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;28 NavigationAction action(newURL, policyChecker()->loadType(), isFormSubmission);29 30 oldDocumentLoader->setTriggeringAction(action);31 policyChecker()->stopCheck();32 policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,33 callContinueFragmentScrollAfterNavigationPolicy, this);34 } else {35 if (Frame* parent = m_frame->tree()->parent())36 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());37 38 policyChecker()->stopCheck();39 setPolicyDocumentLoader(loader);40 if (loader->triggeringAction().isEmpty())41 loader->setTriggeringAction(NavigationAction(newURL, policyChecker()->loadType(), isFormSubmission));42 43 if (Element* ownerElement = m_frame->ownerElement()) {44 // We skip dispatching the beforeload event if we've already45 // committed a real document load because the event would leak46 // subsequent activity by the frame which the parent frame isn't47 // supposed to learn. For example, if the child frame navigated to48 // a new URL, the parent frame shouldn't learn the URL.49 if (!m_stateMachine.committedFirstRealDocumentLoad()50 && !ownerElement->dispatchBeforeLoadEvent(loader->request().url().string())) {51 continueLoadAfterNavigationPolicy(loader->request(), formState, false);52 return;53 }54 }55 56 policyChecker()->checkNavigationPolicy(loader->request(), loader, formState,57 callContinueLoadAfterNavigationPolicy, this);58 }59 } 7,FrameLoader::callContinueLoadAfterNavigationPolicy( ... ) 1 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,2 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)3 {4 FrameLoader* loader = static_cast<FrameLoader*>(argument);5 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);6 } 8,FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue) 1 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue) 2 { 3 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a 4 // nil policyDataSource because loading the alternate page will have passed 5 // through this method already, nested; otherwise, policyDataSource should still be set. 6 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty()); 7 8 bool isTargetItem = history()->provisionalItem() ? history()->provisionalItem()->isTargetItem() : false; 9 10 // Two reasons we can't continue:11 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this 12 // is the user responding Cancel to the form repost nag sheet.13 // 2) User responded Cancel to an alert popped up by the before unload event handler.14 bool canContinue = shouldContinue && shouldClose();15 16 if (!canContinue) {17 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 18 // need to report that the client redirect was cancelled.19 if (m_quickRedirectComing)20 clientRedirectCancelledOrFinished(false);21 22 setPolicyDocumentLoader(0);23 24 // If the navigation request came from the back/forward menu, and we punt on it, we have the 25 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity, 26 // we only do this when punting a navigation for the target frame or top-level frame. 27 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType())) {28 if (Page* page = m_frame->page()) {29 Frame* mainFrame = page->mainFrame();30 if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) {31 page->backForward()->setCurrentItem(resetItem);32 m_frame->loader()->client()->updateGlobalHistoryItemForPage();33 }34 }35 }36 return;37 }38 39 FrameLoadType type = policyChecker()->loadType();40 // A new navigation is in progress, so don't clear the history's provisional item.41 stopAllLoaders(ShouldNotClearProvisionalItem);42 43 // <rdar://problem/6250856> - In certain circumstances on pages with multiple frames, stopAllLoaders()44 // might detach the current FrameLoader, in which case we should bail on this newly defunct load. 45 if (!m_frame->page())46 return;47 48 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) && ENABLE(INSPECTOR)49 if (Page* page = m_frame->page()) {50 if (page->mainFrame() == m_frame)51 m_frame->page()->inspectorController()->resume();52 }53 #endif54 55 setProvisionalDocumentLoader(m_policyDocumentLoader.get());56 m_loadType = type;57 setState(FrameStateProvisional);58 59 setPolicyDocumentLoader(0);60 61 if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) {62 loadProvisionalItemFromCachedPage();63 return;64 }65 66 if (formState)67 m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);68 else69 continueLoadAfterWillSubmitForm();70 } 9,FrameLoader::loadProvisionalItemFromCachedPage() 1 void FrameLoader::loadProvisionalItemFromCachedPage() 2 { 3 DocumentLoader* provisionalLoader = provisionalDocumentLoader(); 4 LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().string().utf8().data()); 5 6 provisionalLoader->prepareForLoadStart(); 7 8 m_loadingFromCachedPage = true; 9 10 // Should have timing data from previous time(s) the page was shown.11 ASSERT(provisionalLoader->timing()->navigationStart);12 provisionalLoader->resetTiming();13 provisionalLoader->timing()->navigationStart = currentTime(); 14 15 provisionalLoader->setCommitted(true);16 commitProvisionalLoad();17 } 10,FrameLoader::commitProvisionalLoad() 1 void FrameLoader::commitProvisionalLoad() 2 { 3 RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0; 4 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; 5 6 LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(), 7 m_frame->document() ? m_frame->document()->url().string().utf8().data() : "", 8 pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>"); 9 10 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.11 // We are doing this here because we know for sure that a new page is about to be loaded.12 HistoryItem* item = history()->currentItem();13 if (!m_frame->tree()->parent() && PageCache::canCache(m_frame->page()) && !item->isInPageCache())14 pageCache()->add(item, m_frame->page());15 16 if (m_loadType != FrameLoadTypeReplace)17 closeOldDataSources();18 19 if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())20 m_client->makeRepresentation(pdl.get());21 22 transitionToCommitted(cachedPage);23 24 if (pdl) {25 // Check if the destination page is allowed to access the previous page's timing information.26 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());27 m_documentLoader->timing()->hasSameOriginAsPreviousDocument = securityOrigin->canRequest(m_previousUrl);28 }29 30 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's31 // status has changed, if there was a redirect. The frame load delegate may have saved some state about32 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are33 // just about to commit a new page, there cannot possibly be a pending redirect at this point.34 if (m_sentRedirectNotification)35 clientRedirectCancelledOrFinished(false);36 37 if (cachedPage && cachedPage->document()) {38 prepareForCachedPageRestore();39 cachedPage->restore(m_frame->page());40 41 dispatchDidCommitLoad();42 43 // If we have a title let the WebView know about it. 44 StringWithDirection title = m_documentLoader->title();45 if (!title.isNull())46 m_client->dispatchDidReceiveTitle(title);47 48 checkCompleted();49 } else { 50 KURL url = pdl->substituteData().responseURL();51 if (url.isEmpty())52 url = pdl->url();53 if (url.isEmpty())54 url = pdl->responseURL();55 if (url.isEmpty())56 url = blankURL();57 58 didOpenURL(url);59 }60 61 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(),62 m_frame->document() ? m_frame->document()->url().string().utf8().data() : "");63 64 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())65 history()->updateForClientRedirect();66 67 if (m_loadingFromCachedPage) {68 m_frame->document()->documentDidBecomeActive();69 70 // Force a layout to update view size and thereby update scrollbars.71 m_frame->view()->forceLayout();72 73 const ResponseVector& responses = m_documentLoader->responses();74 size_t count = responses.size();75 for (size_t i = 0; i < count; i++) {76 const ResourceResponse& response = responses[i];77 // FIXME: If the WebKit client changes or cancels the request, this is not respected.78 ResourceError error;79 unsigned long identifier;80 ResourceRequest request(response.url());81 requestFromDelegate(request, identifier, error);82 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.83 // However, with today's computers and networking speeds, this won't happen in practice.84 // Could be an issue with a giant local file.85 notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, static_cast<int>(response.expectedContentLength()), 0, error);86 }87 88 pageCache()->remove(history()->currentItem());89 90 m_documentLoader->setPrimaryLoadComplete(true);91 92 // FIXME: Why only this frame and not parent frames?93 checkLoadCompleteForThisFrame();94 }95 } 11,FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage) 1 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage) 2 { 3 ASSERT(m_client->hasWebView()); 4 ASSERT(m_state == FrameStateProvisional); 5 6 if (m_state != FrameStateProvisional) 7 return; 8 9 if (m_frame->view()) 10 m_frame->view()->scrollAnimator()->cancelAnimations(); 11 12 m_client->setCopiesOnScroll(); 13 history()->updateForCommit(); 14 15 // The call to closeURL() invokes the unload event handler, which can execute arbitrary 16 // JavaScript. If the script initiates a new load, we need to abandon the current load, 17 // or the two will stomp each other. 18 DocumentLoader* pdl = m_provisionalDocumentLoader.get(); 19 if (m_documentLoader) 20 closeURL(); 21 if (pdl != m_provisionalDocumentLoader) 22 return; 23 24 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone 25 if (m_documentLoader) 26 m_documentLoader->stopLoadingSubresources(); 27 if (m_documentLoader) 28 m_documentLoader->stopLoadingPlugIns(); 29 30 setDocumentLoader(m_provisionalDocumentLoader.get()); 31 setProvisionalDocumentLoader(0); 32 setState(FrameStateCommittedPage); 33 34 // Handle adding the URL to the back/forward list. 35 DocumentLoader* dl = m_documentLoader.get(); 36 37 switch (m_loadType) { 38 case FrameLoadTypeForward: 39 case FrameLoadTypeBack: 40 case FrameLoadTypeIndexedBackForward: 41 if (m_frame->page()) { 42 // If the first load within a frame is a navigation within a back/forward list that was attached 43 // without any of the items being loaded then we need to update the history in a similar manner as 44 // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>). 45 if (!m_stateMachine.committedFirstRealDocumentLoad()) 46 history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList); 47 48 history()->updateForBackForwardNavigation(); 49 50 // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object 51 if (history()->currentItem() && !cachedPage) 52 m_pendingStateObject = history()->currentItem()->stateObject(); 53 54 // Create a document view for this document, or used the cached view. 55 if (cachedPage) { 56 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader(); 57 ASSERT(cachedDocumentLoader); 58 cachedDocumentLoader->setFrame(m_frame); 59 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame()); 60 61 } else 62 m_client->transitionToCommittedForNewPage(); 63 } 64 break; 65 66 case FrameLoadTypeReload: 67 case FrameLoadTypeReloadFromOrigin: 68 case FrameLoadTypeSame: 69 case FrameLoadTypeReplace: 70 history()->updateForReload(); 71 m_client->transitionToCommittedForNewPage(); 72 break; 73 74 case FrameLoadTypeStandard: 75 history()->updateForStandardLoad(); 76 if (m_frame->view()) 77 m_frame->view()->setScrollbarsSuppressed(true); 78 m_client->transitionToCommittedForNewPage(); 79 break; 80 81 case FrameLoadTypeRedirectWithLockedBackForwardList: 82 history()->updateForRedirectWithLockedBackForwardList(); 83 m_client->transitionToCommittedForNewPage(); 84 break; 85 86 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is). 87 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state. 88 default: 89 ASSERT_NOT_REACHED(); 90 } 91 92 m_documentLoader->writer()->setMIMEType(dl->responseMIMEType()); 93 94 // Tell the client we've committed this URL. 95 ASSERT(m_frame->view()); 96 97 if (m_stateMachine.creatingInitialEmptyDocument()) 98 return; 99 100 if (!m_stateMachine.committedFirstRealDocumentLoad())101 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);102 103 if (!m_client->hasHTMLView())104 receivedFirstData();105 } 12,FrameLoaderClientQt::transitionToCommittedForNewPage() 1 void FrameLoaderClientQt::transitionToCommittedForNewPage() 2 { 3 ASSERT(m_frame); 4 ASSERT(m_webFrame); 5 6 QBrush brush = m_webFrame->page()->palette().brush(QPalette::Base); 7 QColor backgroundColor = brush.style() == Qt::SolidPattern ? brush.color() : QColor(); 8 9 QWebPage* page = m_webFrame->page();10 const QSize preferredLayoutSize = page->preferredContentsSize();11 12 ScrollbarMode hScrollbar = (ScrollbarMode) m_webFrame->scrollBarPolicy(Qt::Horizontal);13 ScrollbarMode vScrollbar = (ScrollbarMode) m_webFrame->scrollBarPolicy(Qt::Vertical);14 bool hLock = hScrollbar != ScrollbarAuto;15 bool vLock = vScrollbar != ScrollbarAuto;16 17 IntSize currentVisibleContentSize = m_frame->view() ? m_frame->view()->actualVisibleContentRect().size() : IntSize();18 19 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);25 26 bool isMainFrame = m_frame == m_frame->page()->mainFrame();27 if (isMainFrame && page->d->client) {28 m_frame->view()->setPaintsEntireContents(page->d->client->viewResizesToContentsEnabled());29 m_frame->view()->setDelegatesScrolling(page->d->client->viewResizesToContentsEnabled());30 }31 32 // The HistoryController will update the scroll position later if needed.33 m_frame->view()->setActualVisibleContentRect(IntRect(IntPoint::zero(), currentVisibleContentSize));34 } 13,Frame::createView( ... ) 1 void Frame::setView(PassRefPtr<FrameView> view) 2 { 3 // We the custom scroll bars as early as possible to prevent m_doc->detach() 4 // from messing with the view such that its scroll bars won't be torn down. 5 // FIXME: We should revisit this. 6 if (m_view) 7 m_view->detachCustomScrollbars(); 8 9 // Detach the document now, so any onUnload handlers get run - if10 // we wait until the view is destroyed, then things won't be11 // hooked up enough for some JavaScript calls to work.12 if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {13 // FIXME: We don't call willRemove here. Why is that OK?14 m_doc->detach();15 }16 17 if (m_view)18 m_view->unscheduleRelayout();19 20 eventHandler()->clear();21 22 m_view = view;23 24 // Only one form submission is allowed per view of a part.25 // Since this part may be getting reused as a result of being26 // pulled from the back/forward cache, reset this flag.27 loader()->resetMultipleFormSubmissionProtection();28 29 #if ENABLE(TILED_BACKING_STORE)30 if (m_view && tiledBackingStore())31 m_view->setPaintsEntireContents(true);32 #endif33 } OK!!! CreateView代码跟踪到此为止!! 3.3 setDocument 1 void setDocument(PassRefPtr<Document>); 描述: 置同Frame关联的Document对象(一般是DocumentWriter创建的)。还是两种情况 实现: 1 void Frame::setDocument(PassRefPtr<Document> newDoc) 2 { 3 ASSERT(!newDoc || newDoc->frame()); 4 if (m_doc && m_doc->attached() && !m_doc->inPageCache()) { 5 // FIXME: We don't call willRemove here. Why is that OK? 6 m_doc->detach(); 7 } 8 9 m_doc = newDoc;10 selection()->updateSecureKeyboardEntryIfActive();11 12 if (m_doc && !m_doc->attached())13 m_doc->attach();14 15 // Update the cached 'document' property, which is now stale.16 m_script.updateDocument();17 18 if (m_page)19 m_page->updateViewportArguments();20 } 函数调用系列: 1 QWebFrame::QwebFrame 2 QwebFramePrivate::init 3 Frame::init 4 FrameLoader::init 5 DocumentWriter::begin 6 Frame::setDocument 7 8 9 DocumentLoader::receivedData10 DocumentLoader::commitLoad11 FrameLoaderClientQt::committedLoad12 DocumentLoader::commitData13 DocumentWriter::setEncoding14 DocumentWriter::willSetEncoding15 FrameLoader::receivedFirstData16 DocumentWriter::begin17 FrameLoader::clear18 Frame::setDocument 代码跟踪(分两种) 1,QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData) 1 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData) 2 : QObject(parent) 3 , d(new QWebFramePrivate) 4 { 5 d->page = parent->d->page; 6 d->init(this, frameData); 7 #if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION) 8 connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged())); 9 d->m_orientation.start();10 #endif11 } 2,QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData) 1 void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData) 2 { 3 q = qframe; 4 5 allowsScrolling = frameData->allowsScrolling; 6 marginWidth = frameData->marginWidth; 7 marginHeight = frameData->marginHeight; 8 frame = frameData->frame.get(); 9 frameLoaderClient = frameData->frameLoaderClient;10 frameLoaderClient->setFrame(qframe, frame);11 12 frame->init();13 } 3,Frame::init() 1 inline void Frame::init()2 {3 m_loader.init();4 } 4,FrameLoader::init() 1 void FrameLoader::init() 2 { 3 // Propagate sandbox attributes to this Frameloader and its descendants. 4 // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin. 5 updateSandboxFlags(); 6 7 // this somewhat odd set of steps is needed to give the frame an initial empty document 8 m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument); 9 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());10 setProvisionalDocumentLoader(m_policyDocumentLoader.get());11 setState(FrameStateProvisional);12 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));13 m_provisionalDocumentLoader->finishedLoading();14 m_documentLoader->writer()->begin(KURL(), false);15 m_documentLoader->writer()->end();16 m_frame->document()->cancelParsing();17 m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);18 m_didCallImplicitClose = true;19 20 m_networkingContext = m_client->createNetworkingContext();21 } 5,DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin) 1 void DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin) 2 { 3 // We need to take a reference to the security origin because |clear| 4 // might destroy the document that owns it. 5 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; 6 7 // We grab a local copy of the URL because it's easy for callers to supply 8 // a URL that will be deallocated during the execution of this function. 9 // For example, see <https://bugs./show_bug.cgi?id=66360>.10 KURL url = urlReference;11 12 // Create a new document before clearing the frame, because it may need to13 // inherit an aliased security context.14 RefPtr<Document> document = createDocument(url);15 16 // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,17 // then replace the document with one whose parser will ignore the incoming data (bug 39323)18 if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))19 document = SinkDocument::create(m_frame, url);20 21 // FIXME: Do we need to consult the content security policy here about blocked plug-ins?22 23 bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));24 m_frame->loader()->clear(resetScripting, resetScripting);25 clear();26 if (resetScripting)27 m_frame->script()->updatePlatformScriptObjects();28 29 m_frame->loader()->setOutgoingReferrer(url);30 m_frame->setDocument(document);31 32 if (m_decoder)33 document->setDecoder(m_decoder.get());34 if (forcedSecurityOrigin)35 document->setSecurityOrigin(forcedSecurityOrigin.get());36 37 m_frame->domWindow()->setURL(document->url());38 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());39 40 m_frame->loader()->didBeginDocument(dispatch);41 42 document->implicitOpen();43 44 if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())45 m_frame->view()->setContentsSize(IntSize());46 } 6,Frame::setDocument(PassRefPtr<Document> newDoc) 情况二: 1,MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) 1 void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) 2 { 3 ASSERT(data); 4 ASSERT(length != 0); 5 6 ASSERT(!m_response.isNull()); 7 8 #if USE(CFNETWORK) || PLATFORM(MAC) 9 // Workaround for <rdar://problem/6060782>10 if (m_response.isNull()) {11 m_response = ResourceResponse(KURL(), "text/html", 0, String(), String());12 if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader())13 documentLoader->setResponse(m_response);14 }15 #endif16 17 // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.18 // See <rdar://problem/6304600> for more details.19 #if !USE(CF)20 ASSERT(!defersLoading());21 #endif22 23 #if ENABLE(OFFLINE_WEB_APPLICATIONS)24 documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce);25 #endif26 27 // The additional processing can do anything including possibly removing the last28 // reference to this object; one example of this is 3266216.29 RefPtr<MainResourceLoader> protect(this);30 31 m_timeOfLastDataReceived = currentTime();32 33 ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);34 } 2,ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) 1 void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) 2 { 3 // The following assertions are not quite valid here, since a subclass 4 // might override didReceiveData in a way that invalidates them. This 5 // happens with the steps listed in 3266216 6 // ASSERT(con == connection); 7 // ASSERT(!m_reachedTerminalState); 8 9 // Protect this in this delegate method since the additional processing can do10 // anything including possibly derefing this; one example of this is Radar 3266216.11 RefPtr<ResourceLoader> protector(this);12 13 addData(data, length, allAtOnce);14 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.15 // However, with today's computers and networking speeds, this won't happen in practice.16 // Could be an issue with a giant local file.17 if (m_sendResourceLoadCallbacks && m_frame)18 frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength));19 } 3,MainResourceLoader::addData(const char* data, int length, bool allAtOnce) 1 void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)2 {3 ResourceLoader::addData(data, length, allAtOnce);4 documentLoader()->receivedData(data, length);5 } 4,DocumentLoader::receivedData(const char* data, int length) 1 void DocumentLoader::receivedData(const char* data, int length)2 { 3 m_gotFirstByte = true;4 if (doesProgressiveLoad(m_response.mimeType()))5 commitLoad(data, length);6 } 5,DocumentLoader::commitLoad(const char* data, int length) 1 void DocumentLoader::commitLoad(const char* data, int length) 2 { 3 // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource 4 // by starting a new load, so retain temporarily. 5 RefPtr<Frame> protectFrame(m_frame); 6 RefPtr<DocumentLoader> protectLoader(this); 7 8 commitIfReady(); 9 FrameLoader* frameLoader = DocumentLoader::frameLoader();10 if (!frameLoader)11 return;12 #if ENABLE(WEB_ARCHIVE)13 if (ArchiveFactory::isArchiveMimeType(response().mimeType()))14 return;15 #endif16 frameLoader->client()->committedLoad(this, data, length);17 } 6,FrameLoaderClientQt::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length) 1 void FrameLoaderClientQt::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length) 2 { 3 if (!m_pluginView) 4 loader->commitData(data, length); 5 6 // We re-check here as the plugin can have been created. 7 if (m_pluginView && m_pluginView->isPluginView()) { 8 if (!m_hasSentResponseToPlugin) { 9 m_pluginView->didReceiveResponse(loader->response());10 // The function didReceiveResponse sets up a new stream to the plug-in.11 // On a full-page plug-in, a failure in setting up this stream can cause the12 // main document load to be cancelled, setting m_pluginView to null.13 if (!m_pluginView)14 return;15 m_hasSentResponseToPlugin = true;16 }17 m_pluginView->didReceiveData(data, length);18 }19 } 7,DocumentLoader::commitData(const char* bytes, int length) 1 void DocumentLoader::commitData(const char* bytes, int length) 2 { 3 // Set the text encoding. This is safe to call multiple times. 4 bool userChosen = true; 5 String encoding = overrideEncoding(); 6 if (encoding.isNull()) { 7 userChosen = false; 8 encoding = response().textEncodingName(); 9 }10 m_writer.setEncoding(encoding, userChosen);11 ASSERT(m_frame->document()->parsing());12 m_writer.addData(bytes, length);13 } 8,DocumentWriter::setEncoding(const String& name, bool userChosen) 1 void DocumentWriter::setEncoding(const String& name, bool userChosen)2 {3 m_frame->loader()->willSetEncoding();4 m_encoding = name;5 m_encodingWasChosenByUser = userChosen;6 } 9,FrameLoader::willSetEncoding() 1 void FrameLoader::willSetEncoding()2 {3 if (!m_workingURL.isEmpty())4 receivedFirstData();5 } 10,FrameLoader::receivedFirstData() 1 void FrameLoader::receivedFirstData() 2 { 3 activeDocumentLoader()->writer()->begin(m_workingURL, false); 4 activeDocumentLoader()->writer()->setDocumentWasLoadedAsPartOfNavigation(); 5 6 dispatchDidCommitLoad(); 7 dispatchDidClearWindowObjectsInAllWorlds(); 8 9 if (m_documentLoader) {10 StringWithDirection ptitle = m_documentLoader->title();11 // If we have a title let the WebView know about it.12 if (!ptitle.isNull())13 m_client->dispatchDidReceiveTitle(ptitle);14 }15 16 m_workingURL = KURL();17 18 double delay;19 String url;20 if (!m_documentLoader)21 return;22 if (m_frame->inViewSourceMode())23 return;24 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))25 return;26 27 if (url.isEmpty())28 url = m_frame->document()->url().string();29 else30 url = m_frame->document()->completeURL(url).string();31 32 m_frame->navigationScheduler()->scheduleRedirect(delay, url);33 } 11,DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin) 1 void DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin) 2 { 3 // We need to take a reference to the security origin because |clear| 4 // might destroy the document that owns it. 5 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; 6 7 // We grab a local copy of the URL because it's easy for callers to supply 8 // a URL that will be deallocated during the execution of this function. 9 // For example, see <https://bugs./show_bug.cgi?id=66360>.10 KURL url = urlReference;11 12 // Create a new document before clearing the frame, because it may need to13 // inherit an aliased security context.14 RefPtr<Document> document = createDocument(url);15 16 // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,17 // then replace the document with one whose parser will ignore the incoming data (bug 39323)18 if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))19 document = SinkDocument::create(m_frame, url);20 21 // FIXME: Do we need to consult the content security policy here about blocked plug-ins?22 23 bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));24 m_frame->loader()->clear(resetScripting, resetScripting);25 clear();26 if (resetScripting)27 m_frame->script()->updatePlatformScriptObjects();28 29 m_frame->loader()->setOutgoingReferrer(url);30 m_frame->setDocument(document);31 32 if (m_decoder)33 document->setDecoder(m_decoder.get());34 if (forcedSecurityOrigin)35 document->setSecurityOrigin(forcedSecurityOrigin.get());36 37 m_frame->domWindow()->setURL(document->url());38 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());39 40 m_frame->loader()->didBeginDocument(dispatch);41 42 document->implicitOpen();43 44 if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())45 m_frame->view()->setContentsSize(IntSize());46 } 12,FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView) 1 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView) 2 { 3 m_frame->editor()->clear(); 4 5 if (!m_needsClear) 6 return; 7 m_needsClear = false; 8 9 if (!m_frame->document()->inPageCache()) {10 m_frame->document()->cancelParsing();11 m_frame->document()->stopActiveDOMObjects();12 if (m_frame->document()->attached()) {13 m_frame->document()->willRemove();14 m_frame->document()->detach();15 16 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());17 }18 }19 20 // Do this after detaching the document so that the unload event works.21 if (clearWindowProperties) {22 m_frame->clearDOMWindow();23 m_frame->script()->clearWindowShell(m_frame->document()->inPageCache());24 }25 26 m_frame->selection()->clear();27 m_frame->eventHandler()->clear();28 if (clearFrameView && m_frame->view())29 m_frame->view()->clear();30 31 // Do not drop the document before the ScriptController and view are cleared32 // as some destructors might still try to access the document.33 m_frame->setDocument(0);34 35 m_subframeLoader.clear();36 37 if (clearScriptObjects)38 m_frame->script()->clearScriptObjects();39 40 m_frame->navigationScheduler()->clear();41 42 m_checkTimer.stop();43 m_shouldCallCheckCompleted = false;44 m_shouldCallCheckLoadComplete = false;45 46 if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())47 m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);48 } 13,Frame::setDocument(PassRefPtr<Document> newDoc) OK! setDocuemnt源码跟踪到此为止! 3.4 init 1 void init(); 描述: Frame对象初始化,会调用 FrameLoader::init 初始化FrameLoader对象 实现: 1 inline void Frame::init()2 {3 m_loader.init();4 } 调用系列: 1 QWebFrame::QWebFrame2 QwebFramePrivate::init3 Frame::init 代码已经跟踪过,见上面 3.5 setPageAndTextZoomFactors 1 void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor); 描述: 设置页面放大因子和文字放大因子。在网页缩放或者改变网页字体大小的时候调用 实现: 1 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor) 2 { 3 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor) 4 return; 5 6 Page* page = this->page(); 7 if (!page) 8 return; 9 10 Document* document = this->document();11 if (!document)12 return;13 14 m_editor.dismissCorrectionPanelAsIgnored();15 16 #if ENABLE(SVG)17 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.18 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.19 if (document->isSVGDocument()) {20 if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())21 return;22 if (document->renderer())23 document->renderer()->setNeedsLayout(true);24 }25 #endif26 27 if (m_pageZoomFactor != pageZoomFactor) {28 if (FrameView* view = this->view()) {29 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.30 IntPoint scrollPosition = view->scrollPosition();31 float percentDifference = (pageZoomFactor / m_pageZoomFactor);32 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));33 }34 }35 36 m_pageZoomFactor = pageZoomFactor;37 m_textZoomFactor = textZoomFactor;38 39 document->recalcStyle(Node::Force);40 41 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())42 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);43 44 if (FrameView* view = this->view()) {45 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())46 view->layout();47 }48 } |
|