diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/editing/VisiblePosition.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/editing/VisiblePosition.cpp')
-rw-r--r-- | Source/WebCore/editing/VisiblePosition.cpp | 193 |
1 files changed, 133 insertions, 60 deletions
diff --git a/Source/WebCore/editing/VisiblePosition.cpp b/Source/WebCore/editing/VisiblePosition.cpp index 9155aaef3..bda4a1476 100644 --- a/Source/WebCore/editing/VisiblePosition.cpp +++ b/Source/WebCore/editing/VisiblePosition.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,6 +30,7 @@ #include "Document.h" #include "FloatQuad.h" #include "HTMLElement.h" +#include "HTMLHtmlElement.h" #include "HTMLNames.h" #include "InlineTextBox.h" #include "Logging.h" @@ -37,6 +38,7 @@ #include "RenderBlock.h" #include "RootInlineBox.h" #include "Text.h" +#include "TextStream.h" #include "VisibleUnits.h" #include "htmlediting.h" #include <stdio.h> @@ -62,8 +64,10 @@ void VisiblePosition::init(const Position& position, EAffinity affinity) m_affinity = DOWNSTREAM; } -VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const +VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const { + if (reachedBoundary) + *reachedBoundary = false; // FIXME: Support CanSkipEditingBoundary ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary); VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity); @@ -71,19 +75,24 @@ VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const if (rule == CanCrossEditingBoundary) return next; - return honorEditingBoundaryAtOrAfter(next); + return honorEditingBoundaryAtOrAfter(next, reachedBoundary); } -VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const +VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const { + if (reachedBoundary) + *reachedBoundary = false; // FIXME: Support CanSkipEditingBoundary ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary); // find first previous DOM position that is visible Position pos = previousVisuallyDistinctCandidate(m_deepPosition); // return null visible position if there is no previous visible position - if (pos.atStartOfTree()) + if (pos.atStartOfTree()) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); + } VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM); ASSERT(prev != *this); @@ -101,7 +110,7 @@ VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) cons if (rule == CanCrossEditingBoundary) return prev; - return honorEditingBoundaryAtOrBefore(prev); + return honorEditingBoundaryAtOrBefore(prev, reachedBoundary); } Position VisiblePosition::leftVisuallyDistinctCandidate() const @@ -173,7 +182,7 @@ Position VisiblePosition::leftVisuallyDistinctCandidate() const if (box->direction() == primaryDirection) { if (!prevBox) { - InlineBox* logicalStart = 0; + InlineBox* logicalStart = nullptr; if (primaryDirection == LTR ? box->root().getLogicalStartBoxWithNode(logicalStart) : box->root().getLogicalEndBoxWithNode(logicalStart)) { box = logicalStart; renderer = &box->renderer(); @@ -252,12 +261,17 @@ Position VisiblePosition::leftVisuallyDistinctCandidate() const } } -VisiblePosition VisiblePosition::left(bool stayInEditableContent) const +VisiblePosition VisiblePosition::left(bool stayInEditableContent, bool* reachedBoundary) const { + if (reachedBoundary) + *reachedBoundary = false; Position pos = leftVisuallyDistinctCandidate(); // FIXME: Why can't we move left from the last position in a tree? - if (pos.atStartOfTree() || pos.atEndOfTree()) + if (pos.atStartOfTree() || pos.atEndOfTree()) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); + } VisiblePosition left = VisiblePosition(pos, DOWNSTREAM); ASSERT(left != *this); @@ -266,7 +280,7 @@ VisiblePosition VisiblePosition::left(bool stayInEditableContent) const return left; // FIXME: This may need to do something different from "before". - return honorEditingBoundaryAtOrBefore(left); + return honorEditingBoundaryAtOrBefore(left, reachedBoundary); } Position VisiblePosition::rightVisuallyDistinctCandidate() const @@ -338,7 +352,7 @@ Position VisiblePosition::rightVisuallyDistinctCandidate() const if (box->direction() == primaryDirection) { if (!nextBox) { - InlineBox* logicalEnd = 0; + InlineBox* logicalEnd = nullptr; if (primaryDirection == LTR ? box->root().getLogicalEndBoxWithNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) { box = logicalEnd; renderer = &box->renderer(); @@ -420,12 +434,17 @@ Position VisiblePosition::rightVisuallyDistinctCandidate() const } } -VisiblePosition VisiblePosition::right(bool stayInEditableContent) const +VisiblePosition VisiblePosition::right(bool stayInEditableContent, bool* reachedBoundary) const { + if (reachedBoundary) + *reachedBoundary = false; Position pos = rightVisuallyDistinctCandidate(); // FIXME: Why can't we move left from the last position in a tree? - if (pos.atStartOfTree() || pos.atEndOfTree()) + if (pos.atStartOfTree() || pos.atEndOfTree()) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); + } VisiblePosition right = VisiblePosition(pos, DOWNSTREAM); ASSERT(right != *this); @@ -434,56 +453,78 @@ VisiblePosition VisiblePosition::right(bool stayInEditableContent) const return right; // FIXME: This may need to do something different from "after". - return honorEditingBoundaryAtOrAfter(right); + return honorEditingBoundaryAtOrAfter(right, reachedBoundary); } -VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const +VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition& position, bool* reachedBoundary) const { - if (pos.isNull()) - return pos; + if (reachedBoundary) + *reachedBoundary = false; + if (position.isNull()) + return position; - Node* highestRoot = highestEditableRoot(deepEquivalent()); + auto* highestRoot = highestEditableRoot(deepEquivalent()); // Return empty position if pos is not somewhere inside the editable region containing this position - if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot)) + if (highestRoot && !position.deepEquivalent().deprecatedNode()->isDescendantOf(*highestRoot)) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); - - // Return pos itself if the two are from the very same editable region, or both are non-editable + } + + // Return position itself if the two are from the very same editable region, or both are non-editable // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too. - if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) - return pos; + if (highestEditableRoot(position.deepEquivalent()) == highestRoot) { + if (reachedBoundary) + *reachedBoundary = *this == position; + return position; + } // Return empty position if this position is non-editable, but pos is editable // FIXME: Move to the previous non-editable region. - if (!highestRoot) + if (!highestRoot) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); + } // Return the last position before pos that is in the same editable region as this position - return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot); + return lastEditablePositionBeforePositionInRoot(position.deepEquivalent(), highestRoot); } -VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const +VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos, bool* reachedBoundary) const { + if (reachedBoundary) + *reachedBoundary = false; if (pos.isNull()) return pos; - Node* highestRoot = highestEditableRoot(deepEquivalent()); + auto* highestRoot = highestEditableRoot(deepEquivalent()); // Return empty position if pos is not somewhere inside the editable region containing this position - if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot)) + if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(*highestRoot)) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); + } // Return pos itself if the two are from the very same editable region, or both are non-editable // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too. - if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) + if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) { + if (reachedBoundary) + *reachedBoundary = *this == pos; return pos; + } // Return empty position if this position is non-editable, but pos is editable // FIXME: Move to the next non-editable region. - if (!highestRoot) + if (!highestRoot) { + if (reachedBoundary) + *reachedBoundary = true; return VisiblePosition(); + } // Return the next position after pos that is in the same editable region as this position return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot); @@ -536,14 +577,17 @@ Position VisiblePosition::canonicalPosition(const Position& passedPosition) // The new position must be in the same editable element. Enforce that first. // Unless the descent is from a non-editable html element to an editable body. - if (node && node->hasTagName(htmlTag) && !node->hasEditableStyle() && node->document().body() && node->document().body()->hasEditableStyle()) - return next.isNotNull() ? next : prev; + if (is<HTMLHtmlElement>(node) && !node->hasEditableStyle()) { + auto* body = node->document().bodyOrFrameset(); + if (body && body->hasEditableStyle()) + return next.isNotNull() ? next : prev; + } Node* editingRoot = editableRootForPosition(position); // If the html element is editable, descending into its body will look like a descent // from non-editable to editable content since rootEditableElement() always stops at the body. - if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.deprecatedNode()->isDocumentNode()) + if ((editingRoot && editingRoot->hasTagName(htmlTag)) || (node && (node->isDocumentNode() || node->isShadowRoot()))) return next.isNotNull() ? next : prev; bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot; @@ -590,15 +634,14 @@ UChar32 VisiblePosition::characterAfter() const return 0; UChar32 ch; - const UChar* characters = textNode->data().deprecatedCharacters(); - U16_NEXT(characters, offset, length, ch); + U16_NEXT(textNode->data(), offset, length, ch); return ch; } LayoutRect VisiblePosition::localCaretRect(RenderObject*& renderer) const { if (m_deepPosition.isNull()) { - renderer = 0; + renderer = nullptr; return IntRect(); } Node* node = m_deepPosition.anchorNode(); @@ -617,14 +660,11 @@ LayoutRect VisiblePosition::localCaretRect(RenderObject*& renderer) const return renderer->localCaretRect(inlineBox, caretOffset); } -IntRect VisiblePosition::absoluteCaretBounds() const +IntRect VisiblePosition::absoluteCaretBounds(bool* insideFixed) const { - RenderObject* renderer; - LayoutRect localRect = localCaretRect(renderer); - if (localRect.isEmpty() || !renderer) - return IntRect(); - - return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox(); + RenderBlock* renderer = nullptr; + LayoutRect localRect = localCaretRectInRendererForCaretPainting(*this, renderer); + return absoluteBoundsForLocalCaretRect(renderer, localRect, insideFixed); } int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const @@ -644,7 +684,7 @@ int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const return containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y(); } -#ifndef NDEBUG +#if ENABLE(TREE_DEBUGGING) void VisiblePosition::debugPosition(const char* msg) const { @@ -668,15 +708,15 @@ void VisiblePosition::showTreeForThis() const #endif -PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end) +RefPtr<Range> makeRange(const VisiblePosition& start, const VisiblePosition& end) { if (start.isNull() || end.isNull()) - return 0; + return nullptr; Position s = start.deepEquivalent().parentAnchoredEquivalent(); Position e = end.deepEquivalent().parentAnchoredEquivalent(); if (s.isNull() || e.isNull()) - return 0; + return nullptr; return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode()); } @@ -691,31 +731,35 @@ VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity) return VisiblePosition(r->endPosition(), affinity); } -bool setStart(Range *r, const VisiblePosition &visiblePosition) +bool setStart(Range* range, const VisiblePosition& visiblePosition) { - if (!r) + if (!range) return false; + Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent(); - int code = 0; - r->setStart(p.containerNode(), p.offsetInContainerNode(), code); - return code == 0; + if (!p.containerNode()) + return false; + + return !range->setStart(*p.containerNode(), p.offsetInContainerNode()).hasException(); } -bool setEnd(Range *r, const VisiblePosition &visiblePosition) +bool setEnd(Range* range, const VisiblePosition& visiblePosition) { - if (!r) + if (!range) return false; + Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent(); - int code = 0; - r->setEnd(p.containerNode(), p.offsetInContainerNode(), code); - return code == 0; + if (!p.containerNode()) + return false; + + return !range->setEnd(*p.containerNode(), p.offsetInContainerNode()).hasException(); } // FIXME: Maybe this should be deprecated too, like the underlying function? Element* enclosingBlockFlowElement(const VisiblePosition& visiblePosition) { if (visiblePosition.isNull()) - return NULL; + return nullptr; return deprecatedEnclosingBlockFlowElement(visiblePosition.deepEquivalent().deprecatedNode()); } @@ -744,9 +788,38 @@ bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const N return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node); } +bool VisiblePosition::equals(const VisiblePosition& other) const +{ + return m_affinity == other.m_affinity && m_deepPosition.equals(other.m_deepPosition); +} + +TextStream& operator<<(TextStream& stream, EAffinity affinity) +{ + switch (affinity) { + case UPSTREAM: + stream << "upstream"; + break; + case DOWNSTREAM: + stream << "downstream"; + break; + } + return stream; +} + +TextStream& operator<<(TextStream& stream, const VisiblePosition& visiblePosition) +{ + TextStream::GroupScope scope(stream); + stream << "VisiblePosition " << &visiblePosition; + + stream.dumpProperty("position", visiblePosition.deepEquivalent()); + stream.dumpProperty("affinity", visiblePosition.affinity()); + + return stream; +} + } // namespace WebCore -#ifndef NDEBUG +#if ENABLE(TREE_DEBUGGING) void showTree(const WebCore::VisiblePosition* vpos) { |