frame.cpp

来自「linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自Web」· C++ 代码 · 共 1,782 行 · 第 1/4 页

CPP
1,782
字号
/* * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> *                     1999 Lars Knoll <knoll@kde.org> *                     1999 Antti Koivisto <koivisto@kde.org> *                     2000 Simon Hausmann <hausmann@kde.org> *                     2000 Stefan Schimanski <1Stein@gmx.de> *                     2001 George Staikos <staikos@kde.org> * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com> * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008 Eric Seidel <eric@webkit.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#include "config.h"#include "Frame.h"#include "ApplyStyleCommand.h"#include "BeforeUnloadEvent.h"#include "CSSComputedStyleDeclaration.h"#include "CSSProperty.h"#include "CSSPropertyNames.h"#include "CachedCSSStyleSheet.h"#include "DOMWindow.h"#include "DocLoader.h"#include "DocumentType.h"#include "EditingText.h"#include "EditorClient.h"#include "EventNames.h"#include "FocusController.h"#include "FloatQuad.h"#include "FrameLoader.h"#include "FrameView.h"#include "GraphicsContext.h"#include "HTMLDocument.h"#include "HTMLFormElement.h"#include "HTMLFrameElementBase.h"#include "HTMLFormControlElement.h"#include "HTMLNames.h"#include "HTMLTableCellElement.h"#include "HitTestResult.h"#include "Logging.h"#include "markup.h"#include "MediaFeatureNames.h"#include "Navigator.h"#include "NodeList.h"#include "Page.h"#include "RegularExpression.h"#include "RenderPart.h"#include "RenderTableCell.h"#include "RenderTextControl.h"#include "RenderTheme.h"#include "RenderView.h"#include "Settings.h"#include "TextIterator.h"#include "TextResourceDecoder.h"#include "XMLNames.h"#include "ScriptController.h"#include "npruntime_impl.h"#include "visible_units.h"#include <wtf/RefCountedLeakCounter.h>#include <wtf/StdLibExtras.h>#if USE(JSC)#include "JSDOMWindowShell.h"#include "runtime_root.h"#endif#if FRAME_LOADS_USER_STYLESHEET#include "UserStyleSheetLoader.h"#endif#if ENABLE(SVG)#include "SVGDocument.h"#include "SVGDocumentExtensions.h"#include "SVGNames.h"#include "XLinkNames.h"#endif#if ENABLE(WML)#include "WMLNames.h"#endifusing namespace std;namespace WebCore {using namespace HTMLNames;#ifndef NDEBUG    static WTF::RefCountedLeakCounter frameCounter("Frame");#endifstatic inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement){    if (!ownerElement)        return 0;    return ownerElement->document()->frame();}Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)     : m_page(page)    , m_treeNode(this, parentFromOwnerElement(ownerElement))    , m_loader(this, frameLoaderClient)    , m_ownerElement(ownerElement)    , m_script(this)    , m_selectionGranularity(CharacterGranularity)    , m_selectionController(this)    , m_caretBlinkTimer(this, &Frame::caretBlinkTimerFired)    , m_editor(this)    , m_eventHandler(this)    , m_animationController(this)    , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)    , m_caretVisible(false)    , m_caretPaint(true)    , m_highlightTextMatches(false)    , m_inViewSourceMode(false)    , m_needsReapplyStyles(false)    , m_isDisconnected(false)    , m_excludeFromTextSearch(false)#if FRAME_LOADS_USER_STYLESHEET    , m_userStyleSheetLoader(0)#endif{    Frame* parent = parentFromOwnerElement(ownerElement);    m_zoomFactor = parent ? parent->m_zoomFactor : 1.0f;    AtomicString::init();    HTMLNames::init();    QualifiedName::init();    MediaFeatureNames::init();#if ENABLE(SVG)    SVGNames::init();    XLinkNames::init();#endif#if ENABLE(WML)    WMLNames::init();#endif    XMLNames::init();    if (!ownerElement)        page->setMainFrame(this);    else {        page->incrementFrameCount();        // Make sure we will not end up with two frames referencing the same owner element.        ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement));                ownerElement->m_contentFrame = this;    }#ifndef NDEBUG    frameCounter.increment();#endif}Frame::~Frame(){    setView(0);    loader()->clearRecordedFormValues();    loader()->cancelAndClear();        // FIXME: We should not be doing all this work inside the destructor    ASSERT(!m_lifeSupportTimer.isActive());#ifndef NDEBUG    frameCounter.decrement();#endif    if (m_script.haveWindowShell())        m_script.windowShell()->disconnectFrame();    disconnectOwnerElement();        if (m_domWindow)        m_domWindow->disconnectFrame();    HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();    for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)        (*it)->disconnectFrame();                if (m_view) {        m_view->hide();        m_view->clearFrame();    }    ASSERT(!m_lifeSupportTimer.isActive());#if FRAME_LOADS_USER_STYLESHEET    delete m_userStyleSheetLoader;#endif}void Frame::init(){    m_loader.init();}FrameLoader* Frame::loader() const{    return &m_loader;}FrameView* Frame::view() const{    return m_view.get();}void Frame::setView(FrameView* view){    // Detach the document now, so any onUnload handlers get run - if    // we wait until the view is destroyed, then things won't be    // hooked up enough for some JavaScript calls to work.    if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {        // FIXME: We don't call willRemove here. Why is that OK?        m_doc->detach();        if (m_view)            m_view->unscheduleRelayout();    }    eventHandler()->clear();    m_view = view;    // Only one form submission is allowed per view of a part.    // Since this part may be getting reused as a result of being    // pulled from the back/forward cache, reset this flag.    loader()->resetMultipleFormSubmissionProtection();}ScriptController* Frame::script(){    return &m_script;}Document* Frame::document() const{    return m_doc.get();}void Frame::setDocument(PassRefPtr<Document> newDoc){    if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {        // FIXME: We don't call willRemove here. Why is that OK?        m_doc->detach();    }    m_doc = newDoc;    if (m_doc && selection()->isFocusedAndActive())        setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive());            if (m_doc && !m_doc->attached())        m_doc->attach();    // Update the cached 'document' property, which is now stale.    m_script.updateDocument();}Settings* Frame::settings() const{    return m_page ? m_page->settings() : 0;}String Frame::selectedText() const{    return plainText(selection()->toNormalizedRange().get());}IntRect Frame::firstRectForRange(Range* range) const{    int extraWidthToEndOfLine = 0;    ExceptionCode ec = 0;    ASSERT(range->startContainer(ec));    ASSERT(range->endContainer(ec));    InlineBox* startInlineBox;    int startCaretOffset;    range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);    RenderObject* startRenderer = range->startContainer(ec)->renderer();    IntRect startCaretRect = startRenderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);    if (startCaretRect != IntRect())        startCaretRect = startRenderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox();    InlineBox* endInlineBox;    int endCaretOffset;    range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);    RenderObject* endRenderer = range->endContainer(ec)->renderer();    IntRect endCaretRect = endRenderer->localCaretRect(endInlineBox, endCaretOffset);    if (endCaretRect != IntRect())        endCaretRect = endRenderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox();    if (startCaretRect.y() == endCaretRect.y()) {        // start and end are on the same line        return IntRect(min(startCaretRect.x(), endCaretRect.x()),                        startCaretRect.y(),                        abs(endCaretRect.x() - startCaretRect.x()),                       max(startCaretRect.height(), endCaretRect.height()));    }        // start and end aren't on the same line, so go from start to the end of its line    return IntRect(startCaretRect.x(),                    startCaretRect.y(),                   startCaretRect.width() + extraWidthToEndOfLine,                   startCaretRect.height());}SelectionController* Frame::selection() const{    return &m_selectionController;}Editor* Frame::editor() const{    return &m_editor;}TextGranularity Frame::selectionGranularity() const{    return m_selectionGranularity;}void Frame::setSelectionGranularity(TextGranularity granularity){    m_selectionGranularity = granularity;}SelectionController* Frame::dragCaretController() const{    return m_page->dragCaretController();}AnimationController* Frame::animation() const{    return &m_animationController;}static RegularExpression* createRegExpForLabels(const Vector<String>& labels){    // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being    // the same across calls.  We can't do that.    DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));    String pattern("(");    unsigned int numLabels = labels.size();    unsigned int i;    for (i = 0; i < numLabels; i++) {        String label = labels[i];        bool startsWithWordChar = false;        bool endsWithWordChar = false;        if (label.length() != 0) {            startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;            endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;        }                if (i != 0)            pattern.append("|");        // Search for word boundaries only if label starts/ends with "word characters".        // If we always searched for word boundaries, this wouldn't work for languages        // such as Japanese.        if (startsWithWordChar) {            pattern.append("\\b");        }        pattern.append(label);        if (endsWithWordChar) {            pattern.append("\\b");        }    }    pattern.append(")");    return new RegularExpression(pattern, TextCaseInsensitive);}String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell){    RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());    if (cellRenderer && cellRenderer->isTableCell()) {        RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);        if (cellAboveRenderer) {            HTMLTableCellElement* aboveCell =                static_cast<HTMLTableCellElement*>(cellAboveRenderer->node());            if (aboveCell) {                // search within the above cell we found for a match                for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {                    if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {                        // For each text chunk, run the regexp                        String nodeString = n->nodeValue();                        int pos = regExp->searchRev(nodeString);                        if (pos >= 0)                            return nodeString.substring(pos, regExp->matchedLength());                    }                }            }        }    }    // Any reason in practice to search all cells in that are above cell?    return String();}String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element){    OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));    // We stop searching after we've seen this many chars    const unsigned int charsSearchedThreshold = 500;    // This is the absolute max we search.  We allow a little more slop than    // charsSearchedThreshold, to make it more likely that we'll search whole nodes.    const unsigned int maxCharsSearched = 600;    // If the starting element is within a table, the cell that contains it    HTMLTableCellElement* startingTableCell = 0;    bool searchedCellAbove = false;    // walk backwards in the node tree, until another element, or form, or end of tree    int unsigned lengthSearched = 0;    Node* n;    for (n = element->traversePreviousNode();         n && lengthSearched < charsSearchedThreshold;         n = n->traversePreviousNode())    {        if (n->hasTagName(formTag)            || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))        {            // We hit another form element or the start of the form - bail out            break;        } else if (n->hasTagName(tdTag) && !startingTableCell) {            startingTableCell = static_cast<HTMLTableCellElement*>(n);        } else if (n->hasTagName(trTag) && startingTableCell) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?