summaryrefslogtreecommitdiffstats
path: root/WebCore/page/Frame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page/Frame.cpp')
-rw-r--r--WebCore/page/Frame.cpp212
1 files changed, 75 insertions, 137 deletions
diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp
index 7e81b3d..947cb06 100644
--- a/WebCore/page/Frame.cpp
+++ b/WebCore/page/Frame.cpp
@@ -36,6 +36,7 @@
#include "CSSProperty.h"
#include "CSSPropertyNames.h"
#include "CachedCSSStyleSheet.h"
+#include "Chrome.h"
#include "DOMWindow.h"
#include "DocLoader.h"
#include "DocumentType.h"
@@ -74,6 +75,7 @@
#include "TextIterator.h"
#include "TextResourceDecoder.h"
#include "UserContentURLPattern.h"
+#include "XMLNSNames.h"
#include "XMLNames.h"
#include "htmlediting.h"
#include "markup.h"
@@ -82,7 +84,7 @@
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/StdLibExtras.h>
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
#import <Carbon/Carbon.h>
#endif
@@ -136,7 +138,6 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient*
, m_script(this)
, m_selectionGranularity(CharacterGranularity)
, m_selectionController(this)
- , m_caretBlinkTimer(this, &Frame::caretBlinkTimerFired)
, m_editor(this)
, m_eventHandler(this)
, m_animationController(this)
@@ -144,8 +145,6 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient*
#if ENABLE(ORIENTATION_EVENTS)
, m_orientation(0)
#endif
- , m_caretVisible(false)
- , m_caretPaint(true)
, m_highlightTextMatches(false)
, m_inViewSourceMode(false)
, m_needsReapplyStyles(false)
@@ -173,6 +172,7 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient*
MathMLNames::init();
#endif
+ XMLNSNames::init();
XMLNames::init();
if (!ownerElement)
@@ -419,7 +419,7 @@ static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
return new RegularExpression(pattern, TextCaseInsensitive);
}
-String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
+String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
{
RenderObject* cellRenderer = cell->renderer();
@@ -433,23 +433,30 @@ String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellE
if (aboveCell) {
// search within the above cell we found for a match
+ size_t lengthSearched = 0;
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)
+ if (pos >= 0) {
+ if (resultDistanceFromStartOfCell)
+ *resultDistanceFromStartOfCell = lengthSearched;
return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
}
}
}
}
}
// Any reason in practice to search all cells in that are above cell?
+ if (resultDistanceFromStartOfCell)
+ *resultDistanceFromStartOfCell = notFound;
return String();
}
-String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element)
+String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
{
OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
// We stop searching after we've seen this many chars
@@ -461,6 +468,11 @@ String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element
HTMLTableCellElement* startingTableCell = 0;
bool searchedCellAbove = false;
+ if (resultDistance)
+ *resultDistance = notFound;
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = false;
+
// walk backwards in the node tree, until another element, or form, or end of tree
int unsigned lengthSearched = 0;
Node* n;
@@ -476,9 +488,12 @@ String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element
} else if (n->hasTagName(tdTag) && !startingTableCell) {
startingTableCell = static_cast<HTMLTableCellElement*>(n);
} else if (n->hasTagName(trTag) && startingTableCell) {
- String result = searchForLabelsAboveCell(regExp.get(), startingTableCell);
- if (!result.isEmpty())
+ String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
+ if (!result.isEmpty()) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
return result;
+ }
searchedCellAbove = true;
} else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
// For each text chunk, run the regexp
@@ -487,38 +502,48 @@ String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element
if (lengthSearched + nodeString.length() > maxCharsSearched)
nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
int pos = regExp->searchRev(nodeString);
- if (pos >= 0)
+ if (pos >= 0) {
+ if (resultDistance)
+ *resultDistance = lengthSearched;
return nodeString.substring(pos, regExp->matchedLength());
+ }
lengthSearched += nodeString.length();
}
}
// If we started in a cell, but bailed because we found the start of the form or the
// previous element, we still might need to search the row above us for a label.
- if (startingTableCell && !searchedCellAbove)
- return searchForLabelsAboveCell(regExp.get(), startingTableCell);
+ if (startingTableCell && !searchedCellAbove) {
+ String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
+ if (!result.isEmpty()) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ }
return String();
}
-String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
+static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
{
- String name = element->getAttribute(nameAttr);
- if (name.isEmpty())
+ if (stringToMatch.isEmpty())
return String();
- // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
- replace(name, RegularExpression("\\d", TextCaseSensitive), " ");
- name.replace('_', ' ');
+ String mutableStringToMatch = stringToMatch;
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
+ mutableStringToMatch.replace('_', ' ');
+
OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
- // Use the largest match we can find in the whole name string
+ // Use the largest match we can find in the whole string
int pos;
int length;
int bestPos = -1;
int bestLength = -1;
int start = 0;
do {
- pos = regExp->match(name, start);
+ pos = regExp->match(mutableStringToMatch, start);
if (pos != -1) {
length = regExp->matchedLength();
if (length >= bestLength) {
@@ -528,11 +553,24 @@ String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* e
start = pos + 1;
}
} while (pos != -1);
-
+
if (bestPos != -1)
- return name.substring(bestPos, bestLength);
+ return mutableStringToMatch.substring(bestPos, bestLength);
return String();
}
+
+String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
+{
+ // Match against the name element, then against the id element if no match is found for the name element.
+ // See 7538330 for one popular site that benefits from the id element check.
+ // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
+ // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
+ String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
+ if (!resultFromNameAttribute.isEmpty())
+ return resultFromNameAttribute;
+
+ return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
+}
const VisibleSelection& Frame::mark() const
{
@@ -560,31 +598,6 @@ void Frame::notifyRendererOfSelectionChange(bool userTriggered)
toRenderTextControl(renderer)->selectionChanged(userTriggered);
}
-void Frame::invalidateSelection()
-{
- selection()->setNeedsLayout();
- selectionLayoutChanged();
-}
-
-void Frame::setCaretVisible(bool flag)
-{
- if (m_caretVisible == flag)
- return;
- clearCaretRectIfNeeded();
- m_caretVisible = flag;
- selectionLayoutChanged();
-}
-
-void Frame::clearCaretRectIfNeeded()
-{
-#if ENABLE(TEXT_CARET)
- if (m_caretPaint) {
- m_caretPaint = false;
- selection()->invalidateCaretRect();
- }
-#endif
-}
-
// Helper function that tells whether a particular node is an element that has an entire
// Frame and FrameView, a <frame>, <iframe>, or <object>.
static bool isFrameElement(const Node *n)
@@ -637,87 +650,6 @@ void Frame::setFocusedNodeIfNeeded()
page()->focusController()->setFocusedNode(0, this);
}
-void Frame::selectionLayoutChanged()
-{
- bool caretRectChanged = selection()->recomputeCaretRect();
-
-#if ENABLE(TEXT_CARET)
- bool caretBrowsing = settings() && settings()->caretBrowsingEnabled();
- bool shouldBlink = m_caretVisible
- && selection()->isCaret() && (selection()->isContentEditable() || caretBrowsing);
-
- // If the caret moved, stop the blink timer so we can restart with a
- // black caret in the new location.
- if (caretRectChanged || !shouldBlink)
- m_caretBlinkTimer.stop();
-
- // Start blinking with a black caret. Be sure not to restart if we're
- // already blinking in the right location.
- if (shouldBlink && !m_caretBlinkTimer.isActive()) {
- if (double blinkInterval = page()->theme()->caretBlinkInterval())
- m_caretBlinkTimer.startRepeating(blinkInterval);
-
- if (!m_caretPaint) {
- m_caretPaint = true;
- selection()->invalidateCaretRect();
- }
- }
-#else
- if (!caretRectChanged)
- return;
-#endif
-
- RenderView* view = contentRenderer();
- if (!view)
- return;
-
- VisibleSelection selection = this->selection()->selection();
-
- if (!selection.isRange())
- view->clearSelection();
- else {
- // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
- // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3]
- // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
- // and will fill the gap before 'bar'.
- Position startPos = selection.start();
- if (startPos.downstream().isCandidate())
- startPos = startPos.downstream();
- Position endPos = selection.end();
- if (endPos.upstream().isCandidate())
- endPos = endPos.upstream();
-
- // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
- // because we don't yet notify the SelectionController of text removal.
- if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
- RenderObject *startRenderer = startPos.node()->renderer();
- RenderObject *endRenderer = endPos.node()->renderer();
- view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
- }
- }
-}
-
-void Frame::caretBlinkTimerFired(Timer<Frame>*)
-{
-#if ENABLE(TEXT_CARET)
- ASSERT(m_caretVisible);
- ASSERT(selection()->isCaret());
- bool caretPaint = m_caretPaint;
- if (selection()->isCaretBlinkingSuspended() && caretPaint)
- return;
- m_caretPaint = !caretPaint;
- selection()->invalidateCaretRect();
-#endif
-}
-
-void Frame::paintCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const
-{
-#if ENABLE(TEXT_CARET)
- if (m_caretPaint && m_caretVisible)
- selection()->paintCaret(p, tx, ty, clipRect);
-#endif
-}
-
void Frame::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const
{
#if ENABLE(TEXT_CARET)
@@ -779,6 +711,13 @@ void Frame::setZoomFactor(float percent, bool isTextOnly)
}
#endif
+ if (!isTextOnly) {
+ // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
+ IntPoint scrollPosition = view()->scrollPosition();
+ float percentDifference = (percent / m_zoomFactor);
+ view()->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
+ }
+
m_zoomFactor = percent;
m_page->settings()->setZoomsTextOnly(isTextOnly);
@@ -922,12 +861,12 @@ bool Frame::isContentEditable() const
return m_doc->inDesignMode();
}
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
const short enableRomanKeyboardsOnly = -23;
#endif
void Frame::setUseSecureKeyboardEntry(bool enable)
{
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
if (enable == IsSecureEventInputEnabled())
return;
if (enable) {
@@ -1570,12 +1509,6 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig
continue;
}
- // A non-collapsed result range can in some funky whitespace cases still not
- // advance the range's start position (4509328). Break to avoid infinite loop.
- VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
- if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
- break;
-
// Only treat the result as a match if it is visible
if (editor()->insideVisibleArea(resultRange.get())) {
++matchCount;
@@ -1586,7 +1519,12 @@ unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsig
if (limit > 0 && matchCount >= limit)
break;
- setStart(searchRange.get(), newStart);
+ // Set the new start for the search range to be the end of the previous
+ // result range. There is no need to use a VisiblePosition here,
+ // since findPlainText will use a TextIterator to go over the visible
+ // text nodes.
+ searchRange->setStart(resultRange->endContainer(exception), resultRange->endOffset(exception), exception);
+
Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
if (searchRange->collapsed(exception) && shadowTreeRoot)
searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception);