|
|
Chromium Code Reviews|
Created:
4 years, 4 months ago by Andrey Kraynov Modified:
4 years, 4 months ago CC:
blink-reviews, blink-reviews-dom_chromium.org, blink-reviews-style_chromium.org, chromium-reviews, dglazkov+blink, eae+blinkwatch, kinuko+watch, rwlbuis, sof, webcomponents-bugzilla_chromium.org Base URL:
https://chromium.googlesource.com/chromium/src.git@master Target Ref:
refs/pending/heads/master Project:
chromium Visibility:
Public. |
DescriptionIntroduce EphemeralRange::nodes() helper to traverse over a range.
New |EphemeralRange::nodes()| function can help to avoid creating Range objects
when iterating over range nodes.
BUG=388681
TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*"
Committed: https://crrev.com/3bb329fd3811a6914fd08f66d882bf1b36b940cf
Cr-Commit-Position: refs/heads/master@{#413081}
Patch Set 1 #
Total comments: 9
Patch Set 2 : Add null object check #Patch Set 3 : Add missing test file. #
Total comments: 6
Patch Set 4 : Move inRange() to EphemeralRange::nodes() #
Total comments: 11
Patch Set 5 : Address review remarks. #Patch Set 6 : Move default template to right place #Messages
Total messages: 29 (9 generated)
iceman@yandex-team.ru changed reviewers: + yosin@chromium.org
Hi! Here is CL with extracted inRange() helper function, as yosin@ suggested in https://codereview.chromium.org/2246143004/#msg3 comment. Also I tried to make some tests. Could you take a look at this CL, please? https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.h (right): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.h:57: using TraversalNodeType = Node; This is to use FlatTreeTraversal in the same way as NodeTraversal. https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/editing/EditingStyle.cpp (left): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EditingStyle.cpp:1403: Node* pastLast = Range::create(*end.document(), position.parentAnchoredEquivalent(), end.parentAnchoredEquivalent())->pastLastNode(); This is an example how we can avoid creating Range objects now. https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EditingStyle.cpp:1404: for (Node* n = node; n && n != pastLast; n = NodeTraversal::next(*n)) { I have a question about check |n && n != pastLast|. My version of |inRange| currently uses TraversalNextIterator that won't check for NULL objects returned from NodeTraversal::next. Should I create and use special CheckedNextIterator instead of TraversalNextIterator? Is that check really makes sence? https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/editing/EphemeralRange.h (right): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EphemeralRange.h:122: internal::RangeTraversal inRange(const Position& start, const Position& end); Should I move these functions to some static class like RangeTraversal?
yosin@chromium.org changed reviewers: + tkent@chromium.org
+tkent@ for second opinion and OWNERS Which is better? - (global) inRange() - EphemralRange::nodes() - another option https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.h (right): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/dom/shadow/FlatTreeTraversal.h:57: using TraversalNodeType = Node; On 2016/08/16 at 10:02:11, Andrey Kraynov wrote: > This is to use FlatTreeTraversal in the same way as NodeTraversal. ACK https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/editing/EditingStyle.cpp (left): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EditingStyle.cpp:1403: Node* pastLast = Range::create(*end.document(), position.parentAnchoredEquivalent(), end.parentAnchoredEquivalent())->pastLastNode(); On 2016/08/16 at 10:02:11, Andrey Kraynov wrote: > This is an example how we can avoid creating Range objects now. ACK We should avoid to use |Position::compouteContainerNode()| instead of |Position::parentAnchoredEquivalenent()|. However, we've not found an example for diff of |computeContainerNode()| and |parentAnchoredEquivalenent()| yet. https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EditingStyle.cpp:1404: for (Node* n = node; n && n != pastLast; n = NodeTraversal::next(*n)) { On 2016/08/16 at 10:02:11, Andrey Kraynov wrote: > I have a question about check |n && n != pastLast|. > My version of |inRange| currently uses TraversalNextIterator that won't check for NULL objects returned from NodeTraversal::next. > Should I create and use special CheckedNextIterator instead of TraversalNextIterator? > Is that check really makes sence? Please add |DCHECK(n)| just in case. |n| should not be |nullptr| in range. What happened when we pass empty range to |inRange()|? https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/editing/EphemeralRange.h (right): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EphemeralRange.h:122: internal::RangeTraversal inRange(const Position& start, const Position& end); On 2016/08/16 at 10:02:11, Andrey Kraynov wrote: > Should I move these functions to some static class like RangeTraversal? I don't think so. How about EphmeralRange::nodes()? # Example Current: for (Node* node = range.startPosition().nodeAsRangeFirstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) { inRange: for (Node& node : inRange(range)) { nodes: for (Node& node : EphemeralRange(range).nodes()) { # Example 2 inRange: for (Node& node : inRange(start, end)) nodes: for (Node& node : EphmeralRange(start, end)::nodes()) {
> Which is better? > - (global) inRange() > - EphemralRange::nodes() > - another option I don't have a strong opinion. However EphemeralRange::nodes() looks slightly better because such iterations are frequently used with EphemeralRange and EphemeralRange creation is cheap. https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRange.h (right): https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:98: namespace internal { We shouldn't add |internal| namespace. These template classes can be used outside of EphemeralRange class. https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:128: using RangeTraversal = TraversalRangeImpl<CheckedTraversalNextIterator<NodeTraversal>>; We shouldn't put them in |internal| namespace. These classes are used outside of EphemeralRange class. https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp (right): https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp:1: // Copyright 2015 The Chromium Authors. All rights reserved. 2015 -> 2016
Description was changed from ========== Introduce inRange() helper to traverse over an EphemeralRange. New |inRange()| traverse helper can help to avoid create Range objects when iterating over two Positions. BUG=388681 TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*" ========== to ========== Introduce EphemeralRange::nodes() helper to traverse over a range. New |EphemeralRange::nodes()| function can help to avoid creating Range objects when iterating over range nodes. BUG=388681 TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*" ==========
Thanks for helpful comments! I moved inRange() to EphemeralRange::nodes() member function and removed version that takes two Positions as arguments. PTAL. https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... File third_party/WebKit/Source/core/editing/EditingStyle.cpp (left): https://codereview.chromium.org/2251703002/diff/1/third_party/WebKit/Source/c... third_party/WebKit/Source/core/editing/EditingStyle.cpp:1404: for (Node* n = node; n && n != pastLast; n = NodeTraversal::next(*n)) { On 2016/08/17 01:45:31, Yosi_UTC9 wrote: > Please add |DCHECK(n)| just in case. |n| should not be |nullptr| in range. Done. > What happened when we pass empty range to |inRange()|? I expect no iterations in this case. Added a test for it. https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRange.h (right): https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:98: namespace internal { On 2016/08/17 02:05:02, tkent wrote: > We shouldn't add |internal| namespace. These template classes can be used > outside of EphemeralRange class. Done. https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:128: using RangeTraversal = TraversalRangeImpl<CheckedTraversalNextIterator<NodeTraversal>>; On 2016/08/17 02:05:02, tkent wrote: > We shouldn't put them in |internal| namespace. These classes are used outside > of EphemeralRange class. Done. https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp (right): https://codereview.chromium.org/2251703002/diff/40001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp:1: // Copyright 2015 The Chromium Authors. All rights reserved. On 2016/08/17 02:05:02, tkent wrote: > 2015 -> 2016 Done.
Also I have a POC for custom iteration, e.g
for (Node& n : EphemeralRange(...).nodes([](Node& n) { return
NodeTraversal::nextSkippingChildren(n); })) {
std::cout << n << std::endl;
}
or
for (Node& n : EphemeralRange(...).nodes(&NodeTraversal::nextSkippingChildren))
{
std::cout << n << std::endl;
}
It looks like that -
https://gist.github.com/dreamer-dead/3d5f770324a5cc370cd9121ce743e722
Could it be interesting?
For example that will allow to avoid ugly manual for-loop in
https://codereview.chromium.org/2251703002/patch/60001/70007
On 2016/08/17 at 14:09:29, iceman wrote:
> Also I have a POC for custom iteration, e.g
>
> for (Node& n : EphemeralRange(...).nodes([](Node& n) { return
NodeTraversal::nextSkippingChildren(n); })) {
> std::cout << n << std::endl;
> }
>
> or
>
> for (Node& n :
EphemeralRange(...).nodes(&NodeTraversal::nextSkippingChildren)) {
> std::cout << n << std::endl;
> }
>
> It looks like that -
https://gist.github.com/dreamer-dead/3d5f770324a5cc370cd9121ce743e722
> Could it be interesting?
> For example that will allow to avoid ugly manual for-loop in
https://codereview.chromium.org/2251703002/patch/60001/70007
I feel having customer step-function is bit complex.
I can't image what nodes in
|EphmeralRange(...).node(&NodeTraversal::nextSkippinGchildren))| intuitively.
Ugliness of example code fragment comes from iterating with modification.
DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss
Vector<Node> linkOrStyleElements;
for (Node& node : m_slectionToDelete.toNormalizedEphemeralRange().nodes()) {
if (!isHTMLStyleElement(node) && !isHTMLLinkELement(node))
continue;
linkOrStyleElements.append(ndoe);
}
for (Node& node : linkOrStyleEements) {
Element* rootEditable = rootEditableElement(node);
if (!rootEditable)
continue;
removeNode(&node, editingState);
appendNode(&node, element, editingState);
}
https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRange.h (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:44: void operator++() Interesting, I never know we can implement |operator++()| to return |void|. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:49: bool isNull() const { return !m_current; } We may not want to have |isNull()| and |setCurrent()|. Let's revise impl of |DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss()|. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp:13: namespace { We don't need to have anonymous namespace for test class since namespace of test name is global in --gtest_filter of gTest. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp:41: for (Node& node : range.nodes()) { nit: s/Node&/const Node&/ nit: No need to have |{}| https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp:441: for (auto it = iterableRange.begin(), end = iterableRange.end(); !it.isNull() && it != end;) { We could write this loop as (copied from another message): by using node generator loop and node processing loop Vector<Node> linkOrStyleElements; for (Node& node : m_slectionToDelete.toNormalizedEphemeralRange().nodes()) { if (!isHTMLStyleElement(node) && !isHTMLLinkELement(node)) continue; linkOrStyleElements.append(ndoe); } for (Node& node : linkOrStyleEements) { Element* rootEditable = rootEditableElement(node); if (!rootEditable) continue; removeNode(&node, editingState); appendNode(&node, element, editingState); } https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/web/WebLocalFrameImpl.cpp (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/web/WebLocalFrameImpl.cpp:1665: for (Node& n : activeMatchRange.nodes()) { nit: Could you avoid to use one letter variable name |n|?
On 2016/08/18 02:07:53, Yosi_UTC9 wrote:
> I feel having customer step-function is bit complex.
> I can't image what nodes in
> |EphmeralRange(...).node(&NodeTraversal::nextSkippinGchildren))| intuitively.
I agree, it looks complex.
That's what I was worried about.
>
> Ugliness of example code fragment comes from iterating with modification.
>
DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss
>
> Vector<Node> linkOrStyleElements;
> for (Node& node : m_slectionToDelete.toNormalizedEphemeralRange().nodes()) {
> if (!isHTMLStyleElement(node) && !isHTMLLinkELement(node))
> continue;
> linkOrStyleElements.append(ndoe);
> }
>
> for (Node& node : linkOrStyleEements) {
> Element* rootEditable = rootEditableElement(node);
> if (!rootEditable)
> continue;
> removeNode(&node, editingState);
> appendNode(&node, element, editingState);
> }
That will use some dynamic allocations ;(
If it is OK, I can change this code as you suggested.
Will address all of your remarks, thanks!
On 2016/08/18 at 05:57:41, iceman wrote:
> On 2016/08/18 02:07:53, Yosi_UTC9 wrote:
> > I feel having customer step-function is bit complex.
> > I can't image what nodes in
> > |EphmeralRange(...).node(&NodeTraversal::nextSkippinGchildren))|
intuitively.
>
> I agree, it looks complex.
> That's what I was worried about.
>
> >
> > Ugliness of example code fragment comes from iterating with modification.
> >
DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss
> >
> > Vector<Node> linkOrStyleElements;
> > for (Node& node : m_slectionToDelete.toNormalizedEphemeralRange().nodes()) {
> > if (!isHTMLStyleElement(node) && !isHTMLLinkELement(node))
> > continue;
> > linkOrStyleElements.append(ndoe);
> > }
> >
> > for (Node& node : linkOrStyleEements) {
> > Element* rootEditable = rootEditableElement(node);
> > if (!rootEditable)
> > continue;
> > removeNode(&node, editingState);
> > appendNode(&node, element, editingState);
> > }
>
> That will use some dynamic allocations ;(
> If it is OK, I can change this code as you suggested.
>
> Will address all of your remarks, thanks!
I think readability is more important than execution speed for
document.execCommand().
WTF::Vector employs stack allocation for few elements. In usual case, this may
not
allocate from heap.
On 2016/08/18 02:07:53, Yosi_UTC9 wrote:
> Ugliness of example code fragment comes from iterating with modification.
>
DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss
>
> Vector<Node> linkOrStyleElements;
> for (Node& node : m_slectionToDelete.toNormalizedEphemeralRange().nodes()) {
> if (!isHTMLStyleElement(node) && !isHTMLLinkELement(node))
> continue;
> linkOrStyleElements.append(ndoe);
> }
>
> for (Node& node : linkOrStyleEements) {
> Element* rootEditable = rootEditableElement(node);
> if (!rootEditable)
> continue;
> removeNode(&node, editingState);
> appendNode(&node, element, editingState);
> }
Oh, and one more question.
As I see, the initial version of code will not traverse children of style and
link elements.
But it seems that your code does.
Is it correct in case of HTML like this -
<body><a href="outer"><div></div><a href="inner"></a></a></body>
?
On 2016/08/18 at 06:34:29, iceman wrote:
> On 2016/08/18 02:07:53, Yosi_UTC9 wrote:
> > Ugliness of example code fragment comes from iterating with modification.
> >
DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss
> >
> > Vector<Node> linkOrStyleElements;
> > for (Node& node : m_slectionToDelete.toNormalizedEphemeralRange().nodes()) {
> > if (!isHTMLStyleElement(node) && !isHTMLLinkELement(node))
> > continue;
> > linkOrStyleElements.append(ndoe);
> > }
> >
> > for (Node& node : linkOrStyleEements) {
> > Element* rootEditable = rootEditableElement(node);
> > if (!rootEditable)
> > continue;
> > removeNode(&node, editingState);
> > appendNode(&node, element, editingState);
> > }
>
> Oh, and one more question.
> As I see, the initial version of code will not traverse children of style and
link elements.
> But it seems that your code does.
> Is it correct in case of HTML like this -
>
> <body><a href="outer"><div></div><a href="inner"></a></a></body>
>
> ?
Let's keep original behavior. So, we need to have state machine...
On 2016/08/18 07:13:01, Yosi_UTC9 wrote: > Let's keep original behavior. So, we need to have state machine... OK. Sometimes I think that old good C-style 'while\for' with raw pointers is too powerful thing =)
I reverted my changes in DeleteSelectionCommand.cpp file and address yosin@ review remarks. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRange.h (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:44: void operator++() On 2016/08/18 02:11:09, Yosi_UTC9 wrote: > Interesting, I never know we can implement |operator++()| to return |void|. Yep, |operator++()| is just a regular function =) Although, with |void| it will not allow to write |Iterator next = ++prev;| https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRange.h:49: bool isNull() const { return !m_current; } On 2016/08/18 02:11:09, Yosi_UTC9 wrote: > We may not want to have |isNull()| and |setCurrent()|. > Let's revise impl of > |DeleteSelectionCommand::makeStylingElementsDirectChildrenOfEditableRootToPreventStyleLoss()|. Done. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp:13: namespace { On 2016/08/18 02:11:09, Yosi_UTC9 wrote: > We don't need to have anonymous namespace for test class since namespace of test > name is global in --gtest_filter of gTest. Done. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/core/editing/EphemeralRangeTest.cpp:41: for (Node& node : range.nodes()) { On 2016/08/18 02:11:09, Yosi_UTC9 wrote: > nit: s/Node&/const Node&/ > nit: No need to have |{}| Done. https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... File third_party/WebKit/Source/web/WebLocalFrameImpl.cpp (right): https://codereview.chromium.org/2251703002/diff/60001/third_party/WebKit/Sour... third_party/WebKit/Source/web/WebLocalFrameImpl.cpp:1665: for (Node& n : activeMatchRange.nodes()) { On 2016/08/18 02:11:09, Yosi_UTC9 wrote: > nit: Could you avoid to use one letter variable name |n|? Done.
lgtm
The CQ bit was checked by tkent@chromium.org
lgtm
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
The CQ bit was unchecked by commit-bot@chromium.org
Try jobs failed on following builders: android_arm64_dbg_recipe on master.tryserver.chromium.android (JOB_FAILED, https://build.chromium.org/p/tryserver.chromium.android/builders/android_arm6...)
The CQ bit was checked by iceman@yandex-team.ru
The patchset sent to the CQ was uploaded after l-g-t-m from tkent@chromium.org, yosin@chromium.org Link to the patchset: https://codereview.chromium.org/2251703002/#ps100001 (title: "Move default template to right place")
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/v2/patch-status/codereview.chromium.or...
Message was sent while issue was closed.
Description was changed from ========== Introduce EphemeralRange::nodes() helper to traverse over a range. New |EphemeralRange::nodes()| function can help to avoid creating Range objects when iterating over range nodes. BUG=388681 TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*" ========== to ========== Introduce EphemeralRange::nodes() helper to traverse over a range. New |EphemeralRange::nodes()| function can help to avoid creating Range objects when iterating over range nodes. BUG=388681 TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*" ==========
Message was sent while issue was closed.
Committed patchset #6 (id:100001)
Message was sent while issue was closed.
Description was changed from ========== Introduce EphemeralRange::nodes() helper to traverse over a range. New |EphemeralRange::nodes()| function can help to avoid creating Range objects when iterating over range nodes. BUG=388681 TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*" ========== to ========== Introduce EphemeralRange::nodes() helper to traverse over a range. New |EphemeralRange::nodes()| function can help to avoid creating Range objects when iterating over range nodes. BUG=388681 TEST=webkit_unit_tests --gtest_filter="EphemeralRangeTest.*" Committed: https://crrev.com/3bb329fd3811a6914fd08f66d882bf1b36b940cf Cr-Commit-Position: refs/heads/master@{#413081} ==========
Message was sent while issue was closed.
Patchset 6 (id:??) landed as https://crrev.com/3bb329fd3811a6914fd08f66d882bf1b36b940cf Cr-Commit-Position: refs/heads/master@{#413081} |
