webkit内核分析之 Frame
参考地址: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(RegularExpression*, 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 #endif 119 120 #if ENABLE(MEDIA_STREAM) 121 MediaStreamFrameController* mediaStreamFrameController() const { return m_mediaStreamFrameController.get(); } 122 #endif 123 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 #endif 135 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 interface 181 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 #endif 190 191 #if ENABLE(MEDIA_STREAM) 192 OwnPtr<MediaStreamFrameController> m_mediaStreamFrameController; 193 #endif 194 }
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 loading 30 // an empty document in FrameLoader::init(). But many frames will now be starting an 31 // asynchronous load of url, so we set m_isComplete to false and then check if the load is 32 // actually completed below. (Note that we set m_isComplete to false even for synchronous 33 // 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 loads 45 // cancelled by returning a null ResourceRequest from requestFromDelegate). 46 // In these cases, the synchronous load would have finished 47 // 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 being 49 // 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 to 52 // 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 else 12 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 Create
1 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 }
描述:
调用Frame构造函数,创建出 Frame 对象。 有两个地方会创建 Frame对象: 一个是要加载一个新的页面请求,这时候会创建一个 main frame。 一个是 在加载子帧的时候,通过 FrameLoaderClientQt 的
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::append 11 ...... 12 HTMLTreeBuilder::processToken 13 ...... 14 HTMLElementBase::openURL 15 SubFrameLoader::requestFrame 16 ...... 17 FrameLoaderClientQt::creatFrame 18 QwebFrameData::QwebFrameData 19 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 delegating 10 // the responsibility to the QWidget. This is the code path 11 // 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() const 2 { 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 WebCore 15 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.webkit.org/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 there 12 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. Do 27 // 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 we 11 // end up pumping nothing. It can filter out empty pumps itself. 12 // FIXME: m_input.current().length() is only accurate if we 13 // end up parsing the whole buffer in this pump. We should pass how 14 // 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) fail 28 // http/tests/security/xssAuditor/dom-write-innerHTML.html 29 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 this 37 // 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-enter 10 // the parser. 11 // 12 // FIXME: Top clearing the rawToken once we start running the parser off 13 // the main thread or once we stop allowing synchronous JavaScript 14 // 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() == trTag 156 || 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() == trTag 173 || 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() == basefontTag 203 || token.name() == bgsoundTag 204 || token.name() == linkTag 205 || token.name() == metaTag 206 || token.name() == noframesTag 207 || 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() == captionTag 255 || token.name() == tableTag 256 || isTableBodyContextTag(token.name()) 257 || token.name() == trTag 258 || isTableCellContextTag(token.name())) { 259 parseError(token); 260 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); 261 processEndTag(endSelect); 262 reprocessStartTag(token); 263 return; 264 } 265 // Fall through 266 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() == inputTag 299 || token.name() == keygenTag 300 || 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() == bTag 327 || token.name() == bigTag 328 || token.name() == blockquoteTag 329 || token.name() == bodyTag 330 || token.name() == brTag 331 || token.name() == centerTag 332 || token.name() == codeTag 333 || token.name() == ddTag 334 || token.name() == divTag 335 || token.name() == dlTag 336 || token.name() == dtTag 337 || token.name() == emTag 338 || token.name() == embedTag 339 || isNumberedHeaderTag(token.name()) 340 || token.name() == headTag 341 || token.name() == hrTag 342 || token.name() == iTag 343 || token.name() == imgTag 344 || token.name() == liTag 345 || token.name() == listingTag 346 || token.name() == menuTag 347 || token.name() == metaTag 348 || token.name() == nobrTag 349 || token.name() == olTag 350 || token.name() == pTag 351 || token.name() == preTag 352 || token.name() == rubyTag 353 || token.name() == sTag 354 || token.name() == smallTag 355 || token.name() == spanTag 356 || token.name() == strongTag 357 || token.name() == strikeTag 358 || token.name() == subTag 359 || token.name() == supTag 360 || token.name() == tableTag 361 || token.name() == ttTag 362 || token.name() == uTag 363 || token.name() == ulTag 364 || token.name() == varTag 365 || (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 removed 19 // 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 or 15 // src=javascript), which could try to access the renderer before the normal 16 // parser machinery would call lazyAttach() and set us as needing style 17 // resolve. Any code which expects this to be attached will resolve style 18 // before using renderer(), so this will make sure we attach in time. 19 // FIXME: Normally lazyAttach marks the renderer as attached(), but we don't 20 // want to do that here, as as callers expect to call attach() right after 21 // 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 } else 10 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 else 7 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 loading 30 // an empty document in FrameLoader::init(). But many frames will now be starting an 31 // asynchronous load of url, so we set m_isComplete to false and then check if the load is 32 // actually completed below. (Note that we set m_isComplete to false even for synchronous 33 // 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 loads 45 // cancelled by returning a null ResourceRequest from requestFromDelegate). 46 // In these cases, the synchronous load would have finished 47 // 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 being 49 // 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 to 52 // 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 else 12 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 WebCore 15 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);
描述:
创建出FrameView对象,以用于之后的排版。应用调用这个函数的时候需要传入同排版有关的一些信息,如初始 视窗大小、背景色、滚动条模式等。创建出FrameView以后,即调用Frame::setView设置成当前的FrameView。
实现:
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 - if 10 // we wait until the view is destroyed, then things won't be 11 // 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 being 26 // 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 #endif 33 }
函数调用系列:
1 FrameLoader::commitProvisionalLoad 2 FrameLoader::transitionToCommitted 3 FrameLoaderClientQt::transitionToCommittedForNewPage 4 Frame::createView
跟踪一下代码(同上)
1,QWebView::load(const QUrl &url)
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 } else 11 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're 17 // 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 is 26 // 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 already 45 // committed a real document load because the event would leak 46 // subsequent activity by the frame which the parent frame isn't 47 // supposed to learn. For example, if the child frame navigated to 48 // 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 #endif 54 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 else 69 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's 31 // status has changed, if there was a redirect. The frame load delegate may have saved some state about 32 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are 33 // 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( ... )
14,Frame::setView(PassRefPtr<FrameView> view)
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 - if 10 // we wait until the view is destroyed, then things won't be 11 // 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 being 26 // 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 #endif 33 }
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::receivedData 10 DocumentLoader::commitLoad 11 FrameLoaderClientQt::committedLoad 12 DocumentLoader::commitData 13 DocumentWriter::setEncoding 14 DocumentWriter::willSetEncoding 15 FrameLoader::receivedFirstData 16 DocumentWriter::begin 17 FrameLoader::clear 18 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 #endif 11 }
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.webkit.org/show_bug.cgi?id=66360>. 10 KURL url = urlReference; 11 12 // Create a new document before clearing the frame, because it may need to 13 // 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 #endif 16 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 #endif 22 23 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 24 documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce); 25 #endif 26 27 // The additional processing can do anything including possibly removing the last 28 // 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 do 10 // 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 #endif 16 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 the 12 // 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 else 30 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.webkit.org/show_bug.cgi?id=66360>. 10 KURL url = urlReference; 11 12 // Create a new document before clearing the frame, because it may need to 13 // 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 cleared 32 // 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::QWebFrame 2 QwebFramePrivate::init 3 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 #endif 26 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 }
OK!!!! 完结