Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(520)

Unified Diff: third_party/WebKit/Source/core/editing/VisibleUnitsLine.cpp

Issue 2914793002: Move "line" granularity related functions to VisibleUnitLine.cpp (Closed)
Patch Set: 2017-06-05T14:54:11 Change copyright header in VisibleUnitsLine.cpp Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/editing/VisibleUnits.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/editing/VisibleUnitsLine.cpp
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsLine.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsLine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..624a66267d6c0b6620ffdfc98e00facc41445f91
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/VisibleUnitsLine.cpp
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/VisibleUnits.h"
+
+#include "core/editing/EditingUtilities.h"
+#include "core/editing/RenderedPosition.h"
+#include "core/layout/api/LineLayoutBlockFlow.h"
+#include "core/layout/line/InlineTextBox.h"
+#include "core/layout/line/RootInlineBox.h"
+
+namespace blink {
+
+namespace {
+
+bool HasEditableStyle(const Node& node, EditableType editable_type) {
+ if (editable_type == kHasEditableAXRole) {
+ if (AXObjectCache* cache = node.GetDocument().ExistingAXObjectCache()) {
+ if (cache->RootAXEditableElement(&node))
+ return true;
+ }
+ }
+
+ return HasEditableStyle(node);
+}
+
+Element* RootEditableElement(const Node& node, EditableType editable_type) {
+ if (editable_type == kHasEditableAXRole) {
+ if (AXObjectCache* cache = node.GetDocument().ExistingAXObjectCache())
+ return const_cast<Element*>(cache->RootAXEditableElement(&node));
+ }
+
+ return RootEditableElement(node);
+}
+
+Element* RootAXEditableElementOf(const Position& position) {
+ Node* node = position.ComputeContainerNode();
+ if (!node)
+ return nullptr;
+
+ if (IsDisplayInsideTable(node))
+ node = node->parentNode();
+
+ return RootEditableElement(*node, kHasEditableAXRole);
+}
+
+bool HasAXEditableStyle(const Node& node) {
+ return HasEditableStyle(node, kHasEditableAXRole);
+}
+
+ContainerNode* HighestEditableRoot(const Position& position,
+ EditableType editable_type) {
+ if (editable_type == kHasEditableAXRole) {
+ return HighestEditableRoot(position, RootAXEditableElementOf,
+ HasAXEditableStyle);
+ }
+
+ return HighestEditableRoot(position);
+}
+
+Node* PreviousLeafWithSameEditability(Node* node, EditableType editable_type) {
+ bool editable = HasEditableStyle(*node, editable_type);
+ node = PreviousAtomicLeafNode(*node);
+ while (node) {
+ if (editable == HasEditableStyle(*node, editable_type))
+ return node;
+ node = PreviousAtomicLeafNode(*node);
+ }
+ return nullptr;
+}
+
+Node* NextLeafWithSameEditability(
+ Node* node,
+ EditableType editable_type = kContentIsEditable) {
+ if (!node)
+ return nullptr;
+
+ bool editable = HasEditableStyle(*node, editable_type);
+ node = NextAtomicLeafNode(*node);
+ while (node) {
+ if (editable == HasEditableStyle(*node, editable_type))
+ return node;
+ node = NextAtomicLeafNode(*node);
+ }
+ return nullptr;
+}
+
+enum LineEndpointComputationMode { kUseLogicalOrdering, kUseInlineBoxOrdering };
+template <typename Strategy>
+PositionWithAffinityTemplate<Strategy> StartPositionForLine(
+ const PositionWithAffinityTemplate<Strategy>& c,
+ LineEndpointComputationMode mode) {
+ if (c.IsNull())
+ return PositionWithAffinityTemplate<Strategy>();
+
+ RootInlineBox* root_box =
+ RenderedPosition(c.GetPosition(), c.Affinity()).RootBox();
+ if (!root_box) {
+ // There are VisiblePositions at offset 0 in blocks without
+ // RootInlineBoxes, like empty editable blocks and bordered blocks.
+ PositionTemplate<Strategy> p = c.GetPosition();
+ if (p.AnchorNode()->GetLayoutObject() &&
+ p.AnchorNode()->GetLayoutObject()->IsLayoutBlock() &&
+ !p.ComputeEditingOffset())
+ return c;
+
+ return PositionWithAffinityTemplate<Strategy>();
+ }
+
+ Node* start_node;
+ InlineBox* start_box;
+ if (mode == kUseLogicalOrdering) {
+ start_node = root_box->GetLogicalStartBoxWithNode(start_box);
+ if (!start_node)
+ return PositionWithAffinityTemplate<Strategy>();
+ } else {
+ // Generated content (e.g. list markers and CSS :before and :after
+ // pseudoelements) have no corresponding DOM element, and so cannot be
+ // represented by a VisiblePosition. Use whatever follows instead.
+ start_box = root_box->FirstLeafChild();
+ while (true) {
+ if (!start_box)
+ return PositionWithAffinityTemplate<Strategy>();
+
+ start_node = start_box->GetLineLayoutItem().NonPseudoNode();
+ if (start_node)
+ break;
+
+ start_box = start_box->NextLeafChild();
+ }
+ }
+
+ return PositionWithAffinityTemplate<Strategy>(
+ start_node->IsTextNode()
+ ? PositionTemplate<Strategy>(ToText(start_node),
+ ToInlineTextBox(start_box)->Start())
+ : PositionTemplate<Strategy>::BeforeNode(start_node));
+}
+
+template <typename Strategy>
+PositionWithAffinityTemplate<Strategy> StartOfLineAlgorithm(
+ const PositionWithAffinityTemplate<Strategy>& c) {
+ // TODO: this is the current behavior that might need to be fixed.
+ // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
+ PositionWithAffinityTemplate<Strategy> vis_pos =
+ StartPositionForLine(c, kUseInlineBoxOrdering);
+ return HonorEditingBoundaryAtOrBefore(vis_pos, c.GetPosition());
+}
+
+PositionWithAffinity StartOfLine(const PositionWithAffinity& current_position) {
+ return StartOfLineAlgorithm<EditingStrategy>(current_position);
+}
+
+PositionInFlatTreeWithAffinity StartOfLine(
+ const PositionInFlatTreeWithAffinity& current_position) {
+ return StartOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
+}
+
+LayoutPoint AbsoluteLineDirectionPointToLocalPointInBlock(
+ RootInlineBox* root,
+ LayoutUnit line_direction_point) {
+ DCHECK(root);
+ LineLayoutBlockFlow containing_block = root->Block();
+ FloatPoint absolute_block_point =
+ containing_block.LocalToAbsolute(FloatPoint());
+ if (containing_block.HasOverflowClip())
+ absolute_block_point -= FloatSize(containing_block.ScrolledContentOffset());
+
+ if (root->Block().IsHorizontalWritingMode()) {
+ return LayoutPoint(
+ LayoutUnit(line_direction_point - absolute_block_point.X()),
+ root->BlockDirectionPointInLine());
+ }
+
+ return LayoutPoint(
+ root->BlockDirectionPointInLine(),
+ LayoutUnit(line_direction_point - absolute_block_point.Y()));
+}
+
+} // namespace
+
+// FIXME: consolidate with code in previousLinePosition.
+Position PreviousRootInlineBoxCandidatePosition(
+ Node* node,
+ const VisiblePosition& visible_position,
+ EditableType editable_type) {
+ DCHECK(visible_position.IsValid()) << visible_position;
+ ContainerNode* highest_root =
+ HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
+ Node* previous_node = PreviousLeafWithSameEditability(node, editable_type);
+
+ while (previous_node &&
+ (!previous_node->GetLayoutObject() ||
+ InSameLine(
+ CreateVisiblePosition(FirstPositionInOrBeforeNode(previous_node)),
+ visible_position))) {
+ previous_node =
+ PreviousLeafWithSameEditability(previous_node, editable_type);
+ }
+
+ while (previous_node && !previous_node->IsShadowRoot()) {
+ if (HighestEditableRoot(FirstPositionInOrBeforeNode(previous_node),
+ editable_type) != highest_root)
+ break;
+
+ Position pos = isHTMLBRElement(*previous_node)
+ ? Position::BeforeNode(previous_node)
+ : Position::EditingPositionOf(
+ previous_node, CaretMaxOffset(previous_node));
+
+ if (IsVisuallyEquivalentCandidate(pos))
+ return pos;
+
+ previous_node =
+ PreviousLeafWithSameEditability(previous_node, editable_type);
+ }
+ return Position();
+}
+
+Position NextRootInlineBoxCandidatePosition(
+ Node* node,
+ const VisiblePosition& visible_position,
+ EditableType editable_type) {
+ DCHECK(visible_position.IsValid()) << visible_position;
+ ContainerNode* highest_root =
+ HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
+ Node* next_node = NextLeafWithSameEditability(node, editable_type);
+ while (next_node && (!next_node->GetLayoutObject() ||
+ InSameLine(CreateVisiblePosition(
+ FirstPositionInOrBeforeNode(next_node)),
+ visible_position)))
+ next_node = NextLeafWithSameEditability(next_node, kContentIsEditable);
+
+ while (next_node && !next_node->IsShadowRoot()) {
+ if (HighestEditableRoot(FirstPositionInOrBeforeNode(next_node),
+ editable_type) != highest_root)
+ break;
+
+ Position pos;
+ pos = Position::EditingPositionOf(next_node, CaretMinOffset(next_node));
+
+ if (IsVisuallyEquivalentCandidate(pos))
+ return pos;
+
+ next_node = NextLeafWithSameEditability(next_node, editable_type);
+ }
+ return Position();
+}
+
+// FIXME: Rename this function to reflect the fact it ignores bidi levels.
+VisiblePosition StartOfLine(const VisiblePosition& current_position) {
+ DCHECK(current_position.IsValid()) << current_position;
+ return CreateVisiblePosition(
+ StartOfLine(current_position.ToPositionWithAffinity()));
+}
+
+VisiblePositionInFlatTree StartOfLine(
+ const VisiblePositionInFlatTree& current_position) {
+ DCHECK(current_position.IsValid()) << current_position;
+ return CreateVisiblePosition(
+ StartOfLine(current_position.ToPositionWithAffinity()));
+}
+
+template <typename Strategy>
+static PositionWithAffinityTemplate<Strategy> LogicalStartOfLineAlgorithm(
+ const PositionWithAffinityTemplate<Strategy>& c) {
+ // TODO: this is the current behavior that might need to be fixed.
+ // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
+ PositionWithAffinityTemplate<Strategy> vis_pos =
+ StartPositionForLine(c, kUseLogicalOrdering);
+
+ if (ContainerNode* editable_root = HighestEditableRoot(c.GetPosition())) {
+ if (!editable_root->contains(
+ vis_pos.GetPosition().ComputeContainerNode())) {
+ return PositionWithAffinityTemplate<Strategy>(
+ PositionTemplate<Strategy>::FirstPositionInNode(editable_root));
+ }
+ }
+
+ return HonorEditingBoundaryAtOrBefore(vis_pos, c.GetPosition());
+}
+
+VisiblePosition LogicalStartOfLine(const VisiblePosition& current_position) {
+ DCHECK(current_position.IsValid()) << current_position;
+ return CreateVisiblePosition(LogicalStartOfLineAlgorithm<EditingStrategy>(
+ current_position.ToPositionWithAffinity()));
+}
+
+VisiblePositionInFlatTree LogicalStartOfLine(
+ const VisiblePositionInFlatTree& current_position) {
+ DCHECK(current_position.IsValid()) << current_position;
+ return CreateVisiblePosition(
+ LogicalStartOfLineAlgorithm<EditingInFlatTreeStrategy>(
+ current_position.ToPositionWithAffinity()));
+}
+
+template <typename Strategy>
+static VisiblePositionTemplate<Strategy> EndPositionForLine(
+ const VisiblePositionTemplate<Strategy>& c,
+ LineEndpointComputationMode mode) {
+ DCHECK(c.IsValid()) << c;
+ if (c.IsNull())
+ return VisiblePositionTemplate<Strategy>();
+
+ RootInlineBox* root_box = RenderedPosition(c).RootBox();
+ if (!root_box) {
+ // There are VisiblePositions at offset 0 in blocks without
+ // RootInlineBoxes, like empty editable blocks and bordered blocks.
+ const PositionTemplate<Strategy> p = c.DeepEquivalent();
+ if (p.AnchorNode()->GetLayoutObject() &&
+ p.AnchorNode()->GetLayoutObject()->IsLayoutBlock() &&
+ !p.ComputeEditingOffset())
+ return c;
+ return VisiblePositionTemplate<Strategy>();
+ }
+
+ Node* end_node;
+ InlineBox* end_box;
+ if (mode == kUseLogicalOrdering) {
+ end_node = root_box->GetLogicalEndBoxWithNode(end_box);
+ if (!end_node)
+ return VisiblePositionTemplate<Strategy>();
+ } else {
+ // Generated content (e.g. list markers and CSS :before and :after
+ // pseudo elements) have no corresponding DOM element, and so cannot be
+ // represented by a VisiblePosition. Use whatever precedes instead.
+ end_box = root_box->LastLeafChild();
+ while (true) {
+ if (!end_box)
+ return VisiblePositionTemplate<Strategy>();
+
+ end_node = end_box->GetLineLayoutItem().NonPseudoNode();
+ if (end_node)
+ break;
+
+ end_box = end_box->PrevLeafChild();
+ }
+ }
+
+ PositionTemplate<Strategy> pos;
+ if (isHTMLBRElement(*end_node)) {
+ pos = PositionTemplate<Strategy>::BeforeNode(end_node);
+ } else if (end_box->IsInlineTextBox() && end_node->IsTextNode()) {
+ InlineTextBox* end_text_box = ToInlineTextBox(end_box);
+ int end_offset = end_text_box->Start();
+ if (!end_text_box->IsLineBreak())
+ end_offset += end_text_box->Len();
+ pos = PositionTemplate<Strategy>(ToText(end_node), end_offset);
+ } else {
+ pos = PositionTemplate<Strategy>::AfterNode(end_node);
+ }
+
+ return CreateVisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
+}
+
+// TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
+template <typename Strategy>
+static VisiblePositionTemplate<Strategy> EndOfLineAlgorithm(
+ const VisiblePositionTemplate<Strategy>& current_position) {
+ DCHECK(current_position.IsValid()) << current_position;
+ // TODO(yosin) this is the current behavior that might need to be fixed.
+ // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
+ VisiblePositionTemplate<Strategy> vis_pos =
+ EndPositionForLine(current_position, kUseInlineBoxOrdering);
+
+ // Make sure the end of line is at the same line as the given input
+ // position. Else use the previous position to obtain end of line. This
+ // condition happens when the input position is before the space character
+ // at the end of a soft-wrapped non-editable line. In this scenario,
+ // |endPositionForLine()| would incorrectly hand back a position in the next
+ // line instead. This fix is to account for the discrepancy between lines
+ // with "webkit-line-break:after-white-space" style versus lines without
+ // that style, which would break before a space by default.
+ if (!InSameLine(current_position, vis_pos)) {
+ vis_pos = PreviousPositionOf(current_position);
+ if (vis_pos.IsNull())
+ return VisiblePositionTemplate<Strategy>();
+ vis_pos = EndPositionForLine(vis_pos, kUseInlineBoxOrdering);
+ }
+
+ return HonorEditingBoundaryAtOrAfter(vis_pos,
+ current_position.DeepEquivalent());
+}
+
+// TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
+VisiblePosition EndOfLine(const VisiblePosition& current_position) {
+ return EndOfLineAlgorithm<EditingStrategy>(current_position);
+}
+
+VisiblePositionInFlatTree EndOfLine(
+ const VisiblePositionInFlatTree& current_position) {
+ return EndOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
+}
+
+template <typename Strategy>
+static bool InSameLogicalLine(const VisiblePositionTemplate<Strategy>& a,
+ const VisiblePositionTemplate<Strategy>& b) {
+ DCHECK(a.IsValid()) << a;
+ DCHECK(b.IsValid()) << b;
+ return a.IsNotNull() && LogicalStartOfLine(a).DeepEquivalent() ==
+ LogicalStartOfLine(b).DeepEquivalent();
+}
+
+template <typename Strategy>
+static VisiblePositionTemplate<Strategy> LogicalEndOfLineAlgorithm(
+ const VisiblePositionTemplate<Strategy>& current_position) {
+ DCHECK(current_position.IsValid()) << current_position;
+ // TODO(yosin) this is the current behavior that might need to be fixed.
+ // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
+ VisiblePositionTemplate<Strategy> vis_pos =
+ EndPositionForLine(current_position, kUseLogicalOrdering);
+
+ // Make sure the end of line is at the same line as the given input
+ // position. For a wrapping line, the logical end position for the
+ // not-last-2-lines might incorrectly hand back the logical beginning of the
+ // next line. For example,
+ // <div contenteditable dir="rtl" style="line-break:before-white-space">xyz
+ // a xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz </div>
+ // In this case, use the previous position of the computed logical end
+ // position.
+ if (!InSameLogicalLine(current_position, vis_pos))
+ vis_pos = PreviousPositionOf(vis_pos);
+
+ if (ContainerNode* editable_root =
+ HighestEditableRoot(current_position.DeepEquivalent())) {
+ if (!editable_root->contains(
+ vis_pos.DeepEquivalent().ComputeContainerNode())) {
+ return CreateVisiblePosition(
+ PositionTemplate<Strategy>::LastPositionInNode(editable_root));
+ }
+ }
+
+ return HonorEditingBoundaryAtOrAfter(vis_pos,
+ current_position.DeepEquivalent());
+}
+
+VisiblePosition LogicalEndOfLine(const VisiblePosition& current_position) {
+ return LogicalEndOfLineAlgorithm<EditingStrategy>(current_position);
+}
+
+VisiblePositionInFlatTree LogicalEndOfLine(
+ const VisiblePositionInFlatTree& current_position) {
+ return LogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
+}
+
+template <typename Strategy>
+static bool InSameLineAlgorithm(
+ const PositionWithAffinityTemplate<Strategy>& position1,
+ const PositionWithAffinityTemplate<Strategy>& position2) {
+ if (position1.IsNull() || position2.IsNull())
+ return false;
+ DCHECK_EQ(position1.GetDocument(), position2.GetDocument());
+ DCHECK(!position1.GetDocument()->NeedsLayoutTreeUpdate());
+
+ PositionWithAffinityTemplate<Strategy> start_of_line1 =
+ StartOfLine(position1);
+ PositionWithAffinityTemplate<Strategy> start_of_line2 =
+ StartOfLine(position2);
+ if (start_of_line1 == start_of_line2)
+ return true;
+ PositionTemplate<Strategy> canonicalized1 =
+ CanonicalPositionOf(start_of_line1.GetPosition());
+ if (canonicalized1 == start_of_line2.GetPosition())
+ return true;
+ return canonicalized1 == CanonicalPositionOf(start_of_line2.GetPosition());
+}
+
+bool InSameLine(const PositionWithAffinity& a, const PositionWithAffinity& b) {
+ return InSameLineAlgorithm<EditingStrategy>(a, b);
+}
+
+bool InSameLine(const PositionInFlatTreeWithAffinity& position1,
+ const PositionInFlatTreeWithAffinity& position2) {
+ return InSameLineAlgorithm<EditingInFlatTreeStrategy>(position1, position2);
+}
+
+bool InSameLine(const VisiblePosition& position1,
+ const VisiblePosition& position2) {
+ DCHECK(position1.IsValid()) << position1;
+ DCHECK(position2.IsValid()) << position2;
+ return InSameLine(position1.ToPositionWithAffinity(),
+ position2.ToPositionWithAffinity());
+}
+
+bool InSameLine(const VisiblePositionInFlatTree& position1,
+ const VisiblePositionInFlatTree& position2) {
+ DCHECK(position1.IsValid()) << position1;
+ DCHECK(position2.IsValid()) << position2;
+ return InSameLine(position1.ToPositionWithAffinity(),
+ position2.ToPositionWithAffinity());
+}
+
+template <typename Strategy>
+static bool IsStartOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
+ DCHECK(p.IsValid()) << p;
+ return p.IsNotNull() && p.DeepEquivalent() == StartOfLine(p).DeepEquivalent();
+}
+
+bool IsStartOfLine(const VisiblePosition& p) {
+ return IsStartOfLineAlgorithm<EditingStrategy>(p);
+}
+
+bool IsStartOfLine(const VisiblePositionInFlatTree& p) {
+ return IsStartOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
+}
+
+template <typename Strategy>
+static bool IsEndOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
+ DCHECK(p.IsValid()) << p;
+ return p.IsNotNull() && p.DeepEquivalent() == EndOfLine(p).DeepEquivalent();
+}
+
+bool IsEndOfLine(const VisiblePosition& p) {
+ return IsEndOfLineAlgorithm<EditingStrategy>(p);
+}
+
+bool IsEndOfLine(const VisiblePositionInFlatTree& p) {
+ return IsEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
+}
+
+template <typename Strategy>
+static bool IsLogicalEndOfLineAlgorithm(
+ const VisiblePositionTemplate<Strategy>& p) {
+ DCHECK(p.IsValid()) << p;
+ return p.IsNotNull() &&
+ p.DeepEquivalent() == LogicalEndOfLine(p).DeepEquivalent();
+}
+
+bool IsLogicalEndOfLine(const VisiblePosition& p) {
+ return IsLogicalEndOfLineAlgorithm<EditingStrategy>(p);
+}
+
+bool IsLogicalEndOfLine(const VisiblePositionInFlatTree& p) {
+ return IsLogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
+}
+
+VisiblePosition PreviousLinePosition(const VisiblePosition& visible_position,
+ LayoutUnit line_direction_point,
+ EditableType editable_type) {
+ DCHECK(visible_position.IsValid()) << visible_position;
+
+ Position p = visible_position.DeepEquivalent();
+ Node* node = p.AnchorNode();
+
+ if (!node)
+ return VisiblePosition();
+
+ LayoutObject* layout_object = node->GetLayoutObject();
+ if (!layout_object)
+ return VisiblePosition();
+
+ RootInlineBox* root = nullptr;
+ InlineBox* box = ComputeInlineBoxPosition(visible_position).inline_box;
+ if (box) {
+ root = box->Root().PrevRootBox();
+ // We want to skip zero height boxes.
+ // This could happen in case it is a TrailingFloatsRootInlineBox.
+ if (!root || !root->LogicalHeight() || !root->FirstLeafChild())
+ root = nullptr;
+ }
+
+ if (!root) {
+ Position position = PreviousRootInlineBoxCandidatePosition(
+ node, visible_position, editable_type);
+ if (position.IsNotNull()) {
+ RenderedPosition rendered_position((CreateVisiblePosition(position)));
+ root = rendered_position.RootBox();
+ if (!root)
+ return CreateVisiblePosition(position);
+ }
+ }
+
+ if (root) {
+ // FIXME: Can be wrong for multi-column layout and with transforms.
+ LayoutPoint point_in_line = AbsoluteLineDirectionPointToLocalPointInBlock(
+ root, line_direction_point);
+ LineLayoutItem line_layout_item =
+ root->ClosestLeafChildForPoint(point_in_line, IsEditablePosition(p))
+ ->GetLineLayoutItem();
+ Node* node = line_layout_item.GetNode();
+ if (node && EditingIgnoresContent(*node))
+ return VisiblePosition::InParentBeforeNode(*node);
+ return CreateVisiblePosition(
+ line_layout_item.PositionForPoint(point_in_line));
+ }
+
+ // Could not find a previous line. This means we must already be on the first
+ // line. Move to the start of the content in this block, which effectively
+ // moves us to the start of the line we're on.
+ Element* root_element = HasEditableStyle(*node, editable_type)
+ ? RootEditableElement(*node, editable_type)
+ : node->GetDocument().documentElement();
+ if (!root_element)
+ return VisiblePosition();
+ return VisiblePosition::FirstPositionInNode(root_element);
+}
+
+VisiblePosition NextLinePosition(const VisiblePosition& visible_position,
+ LayoutUnit line_direction_point,
+ EditableType editable_type) {
+ DCHECK(visible_position.IsValid()) << visible_position;
+
+ Position p = visible_position.DeepEquivalent();
+ Node* node = p.AnchorNode();
+
+ if (!node)
+ return VisiblePosition();
+
+ LayoutObject* layout_object = node->GetLayoutObject();
+ if (!layout_object)
+ return VisiblePosition();
+
+ RootInlineBox* root = nullptr;
+ InlineBox* box = ComputeInlineBoxPosition(visible_position).inline_box;
+ if (box) {
+ root = box->Root().NextRootBox();
+ // We want to skip zero height boxes.
+ // This could happen in case it is a TrailingFloatsRootInlineBox.
+ if (!root || !root->LogicalHeight() || !root->FirstLeafChild())
+ root = nullptr;
+ }
+
+ if (!root) {
+ // FIXME: We need do the same in previousLinePosition.
+ Node* child = NodeTraversal::ChildAt(*node, p.ComputeEditingOffset());
+ node = child ? child : &NodeTraversal::LastWithinOrSelf(*node);
+ Position position = NextRootInlineBoxCandidatePosition(
+ node, visible_position, editable_type);
+ if (position.IsNotNull()) {
+ RenderedPosition rendered_position((CreateVisiblePosition(position)));
+ root = rendered_position.RootBox();
+ if (!root)
+ return CreateVisiblePosition(position);
+ }
+ }
+
+ if (root) {
+ // FIXME: Can be wrong for multi-column layout and with transforms.
+ LayoutPoint point_in_line = AbsoluteLineDirectionPointToLocalPointInBlock(
+ root, line_direction_point);
+ LineLayoutItem line_layout_item =
+ root->ClosestLeafChildForPoint(point_in_line, IsEditablePosition(p))
+ ->GetLineLayoutItem();
+ Node* node = line_layout_item.GetNode();
+ if (node && EditingIgnoresContent(*node))
+ return VisiblePosition::InParentBeforeNode(*node);
+ return CreateVisiblePosition(
+ line_layout_item.PositionForPoint(point_in_line));
+ }
+
+ // Could not find a next line. This means we must already be on the last line.
+ // Move to the end of the content in this block, which effectively moves us
+ // to the end of the line we're on.
+ Element* root_element = HasEditableStyle(*node, editable_type)
+ ? RootEditableElement(*node, editable_type)
+ : node->GetDocument().documentElement();
+ if (!root_element)
+ return VisiblePosition();
+ return VisiblePosition::LastPositionInNode(root_element);
+}
+
+} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/editing/VisibleUnits.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698