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

Side by Side Diff: content/common/unique_name_helper.cc

Issue 2902253003: Refactor UniqueNameHelper to use an adapter pattern for code sharing. (Closed)
Patch Set: really address comments 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 unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/unique_name_helper.h" 5 #include "content/common/unique_name_helper.h"
6 6
7 #include <vector> 7 #include <algorithm>
8 8
9 #include "base/containers/adapters.h"
10 #include "base/logging.h" 9 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h" 11 #include "base/strings/string_util.h"
13 #include "content/renderer/render_frame_impl.h"
14 #include "content/renderer/render_frame_proxy.h"
15 #include "third_party/WebKit/public/web/WebLocalFrame.h"
16 12
17 namespace content { 13 namespace content {
18 14
19 namespace { 15 namespace {
20 16
21 const std::string& UniqueNameForFrame(blink::WebFrame* frame) { 17 using FrameAdapter = UniqueNameHelper::FrameAdapter;
22 return frame->IsWebLocalFrame() 18
23 ? RenderFrameImpl::FromWebFrame(frame)->unique_name() 19 class PendingChildFrameAdapter : public UniqueNameHelper::FrameAdapter {
24 : RenderFrameProxy::FromWebFrame(frame)->unique_name(); 20 public:
21 explicit PendingChildFrameAdapter(FrameAdapter* parent) : parent_(parent) {}
22
23 // FrameAdapter overrides:
24 bool IsMainFrame() const override { return false; }
25 bool IsCandidateUnique(const std::string& name) const override {
26 return parent_->IsCandidateUnique(name);
27 }
28 int GetSiblingCount() const override { return parent_->GetChildCount(); }
Charlie Reis 2017/05/25 20:34:25 Might be worth reiterating that this pending child
dcheng 2017/05/25 21:11:16 Done. I tweaked a few comments related to this to
29 int GetChildCount() const override {
30 NOTREACHED();
31 return 0;
32 }
33 std::vector<base::StringPiece> CollectAncestorNames(
34 BeginPoint begin_point,
35 bool (*should_stop)(base::StringPiece)) const override {
36 DCHECK_EQ(BeginPoint::kParentFrame, begin_point);
37 return parent_->CollectAncestorNames(BeginPoint::kThisFrame, should_stop);
38 }
39 std::vector<int> GetFramePosition(BeginPoint begin_point) const override {
40 DCHECK_EQ(BeginPoint::kParentFrame, begin_point);
41 return parent_->GetFramePosition(BeginPoint::kThisFrame);
42 }
43
44 private:
45 FrameAdapter* const parent_;
46 };
47
48 constexpr char kFramePathPrefix[] = "<!--framePath ";
49 constexpr int kFramePathPrefixLength = 14;
50 constexpr int kFramePathSuffixLength = 3;
51
52 bool IsNameWithFramePath(base::StringPiece name) {
53 return name.starts_with(kFramePathPrefix) && name.ends_with("-->") &&
54 (kFramePathPrefixLength + kFramePathSuffixLength) < name.size();
25 } 55 }
26 56
27 bool UniqueNameExists(blink::WebFrame* top, const std::string& candidate) { 57 std::string GenerateCandidate(const FrameAdapter* frame) {
28 // This method is currently O(N), where N = number of frames in the tree. 58 std::string new_name(kFramePathPrefix);
59 new_name += "/";
60 std::vector<base::StringPiece> ancestor_names = frame->CollectAncestorNames(
61 FrameAdapter::BeginPoint::kParentFrame, &IsNameWithFramePath);
62 std::reverse(ancestor_names.begin(), ancestor_names.end());
63 // Note: This checks ancestor_names[0] twice, but it's nicer to do the name
64 // extraction here rather than passing another function pointer to
65 // CollectAncestorNames().
66 if (!ancestor_names.empty() && IsNameWithFramePath(ancestor_names[0])) {
67 ancestor_names[0] = ancestor_names[0].substr(kFramePathPrefixLength,
68 ancestor_names[0].size() -
69 kFramePathPrefixLength -
70 kFramePathSuffixLength);
71 }
72 new_name += base::JoinString(ancestor_names, "/");
29 73
30 // Before recalculating or checking unique name, we set m_uniqueName
31 // to an empty string (so the soon-to-be-removed name does not count
32 // as a collision). This means that uniqueNameExists would return
33 // false positives when called with an empty |name|.
34 DCHECK(!candidate.empty());
35
36 for (blink::WebFrame* frame = top; frame; frame = frame->TraverseNext()) {
37 if (UniqueNameForFrame(frame) == candidate)
38 return true;
39 }
40
41 return false;
42 }
43
44 std::string GenerateCandidate(blink::WebFrame* parent, blink::WebFrame* child) {
45 constexpr char kFramePathPrefix[] = "<!--framePath ";
46 constexpr int kFramePathPrefixLength = 14;
47 constexpr int kFramePathSuffixLength = 3;
48
49 std::string new_name(kFramePathPrefix);
50
51 // Find the nearest parent that has a frame with a path in it.
52 std::vector<blink::WebFrame*> chain;
53 for (blink::WebFrame* frame = parent; frame; frame = frame->Parent()) {
54 base::StringPiece name = UniqueNameForFrame(frame);
55 if (name.starts_with(kFramePathPrefix) && name.ends_with("-->") &&
56 kFramePathPrefixLength + kFramePathSuffixLength < name.size()) {
57 name.substr(kFramePathPrefixLength,
58 name.size() - kFramePathPrefixLength - kFramePathSuffixLength)
59 .AppendToString(&new_name);
60 break;
61 }
62 chain.push_back(frame);
63 }
64
65 for (auto* frame : base::Reversed(chain)) {
66 new_name += '/';
67 new_name += UniqueNameForFrame(frame);
68 }
69
70 int child_count = 0;
71 for (blink::WebFrame* frame = parent->FirstChild(); frame;
72 frame = frame->NextSibling()) {
73 ++child_count;
74 }
75
76 // When generating a candidate, a null |child| means that this is the
77 // candidate name for a child frame that's not yet attached.
78 new_name += "/<!--frame"; 74 new_name += "/<!--frame";
79 new_name += base::IntToString(child_count - (child ? 1 : 0)); 75 new_name += base::IntToString(frame->GetSiblingCount());
80 new_name += "-->-->"; 76 new_name += "-->-->";
81 77
82 // NOTE: This name might not be unique - see http://crbug.com/588800. 78 // NOTE: This name might not be unique - see http://crbug.com/588800.
83 return new_name; 79 return new_name;
84 } 80 }
85 81
86 std::string GenerateFramePosition(blink::WebFrame* parent, 82 std::string GenerateFramePosition(const FrameAdapter* frame) {
87 blink::WebFrame* child) {
88 // This method is currently O(N), where N = number of frames in the tree.
89
90 std::string position_string("<!--framePosition"); 83 std::string position_string("<!--framePosition");
91 84 std::vector<int> positions =
92 while (parent) { 85 frame->GetFramePosition(FrameAdapter::BeginPoint::kParentFrame);
93 int position_in_parent = 0; 86 for (int position : positions) {
94 blink::WebFrame* sibling = parent->FirstChild();
95 while (sibling != child) {
96 sibling = sibling->NextSibling();
97 ++position_in_parent;
98 }
99
100 position_string += '-'; 87 position_string += '-';
101 position_string += base::IntToString(position_in_parent); 88 position_string += base::IntToString(position);
102
103 child = parent;
104 parent = parent->Parent();
105 } 89 }
106 90
107 // NOTE: The generated string is not guaranteed to be unique, but should 91 // NOTE: The generated string is not guaranteed to be unique, but should
108 // have a better chance of being unique than the string generated by 92 // have a better chance of being unique than the string generated by
109 // GenerateCandidate, because we embed extra information into the string: 93 // GenerateCandidate, because we embed extra information into the string:
110 // 1) we walk the full chain of ancestors, all the way to the main frame 94 // 1) we walk the full chain of ancestors, all the way to the main frame
111 // 2) we use frame-position-within-parent (aka |position_in_parent|) 95 // 2) we use frame-position-within-parent (aka |position_in_parent|)
112 // instead of sibling-count. 96 // instead of sibling-count.
113 return position_string; 97 return position_string;
114 } 98 }
115 99
116 std::string AppendUniqueSuffix(blink::WebFrame* top, 100 std::string AppendUniqueSuffix(const FrameAdapter* frame,
117 const std::string& prefix, 101 const std::string& prefix,
118 const std::string& likely_unique_suffix) { 102 const std::string& likely_unique_suffix) {
119 // This should only be called if the |prefix| isn't unique, as this is 103 // This should only be called if the |prefix| isn't unique, as this is
120 // otherwise pointless work. 104 // otherwise pointless work.
121 DCHECK(UniqueNameExists(top, prefix)); 105 DCHECK(!frame->IsCandidateUnique(prefix));
122 106
123 // We want unique name to be stable across page reloads - this is why 107 // We want unique name to be stable across page reloads - this is why
124 // we use a deterministic |number_of_tries| rather than a random number 108 // we use a deterministic |number_of_tries| rather than a random number
125 // (a random number would be more likely to avoid a collision, but 109 // (a random number would be more likely to avoid a collision, but
126 // would change after every page reload). 110 // would change after every page reload).
127 int number_of_retries = 0; 111 int number_of_retries = 0;
128 112
129 // Keep trying |prefix| + |likely_unique_suffix| + |number_of_tries| 113 // Keep trying |prefix| + |likely_unique_suffix| + |number_of_tries|
130 // concatenations until we get a truly unique name. 114 // concatenations until we get a truly unique name.
131 std::string candidate(prefix); 115 std::string candidate(prefix);
132 candidate += likely_unique_suffix; 116 candidate += likely_unique_suffix;
133 candidate += '/'; 117 candidate += '/';
134 while (true) { 118 while (true) {
135 size_t current_length = candidate.size(); 119 size_t current_length = candidate.size();
136 candidate += base::IntToString(number_of_retries++); 120 candidate += base::IntToString(number_of_retries++);
137 candidate += "-->"; 121 candidate += "-->";
138 if (!UniqueNameExists(top, candidate)) 122 if (frame->IsCandidateUnique(candidate))
139 break; 123 break;
140 candidate.resize(current_length); 124 candidate.resize(current_length);
141 } 125 }
142 return candidate; 126 return candidate;
143 } 127 }
144 128
145 std::string CalculateNewName(blink::WebFrame* parent, 129 std::string CalculateNewName(const FrameAdapter* frame,
146 blink::WebFrame* child,
147 const std::string& name) { 130 const std::string& name) {
148 blink::WebFrame* top = parent->Top(); 131 if (!name.empty() && frame->IsCandidateUnique(name) && name != "_blank")
149 if (!name.empty() && !UniqueNameExists(top, name) && name != "_blank")
150 return name; 132 return name;
151 133
152 std::string candidate = GenerateCandidate(parent, child); 134 std::string candidate = GenerateCandidate(frame);
153 if (!UniqueNameExists(top, candidate)) 135 if (frame->IsCandidateUnique(candidate))
154 return candidate; 136 return candidate;
155 137
156 std::string likely_unique_suffix = GenerateFramePosition(parent, child); 138 std::string likely_unique_suffix = GenerateFramePosition(frame);
157 return AppendUniqueSuffix(top, candidate, likely_unique_suffix); 139 return AppendUniqueSuffix(frame, candidate, likely_unique_suffix);
158 } 140 }
159 141
160 } // namespace 142 } // namespace
161 143
162 UniqueNameHelper::UniqueNameHelper(RenderFrameImpl* render_frame) 144 UniqueNameHelper::FrameAdapter::~FrameAdapter() {}
163 : render_frame_(render_frame) {} 145
146 UniqueNameHelper::UniqueNameHelper(FrameAdapter* frame) : frame_(frame) {}
164 147
165 UniqueNameHelper::~UniqueNameHelper() {} 148 UniqueNameHelper::~UniqueNameHelper() {}
166 149
167 std::string UniqueNameHelper::GenerateNameForNewChildFrame( 150 std::string UniqueNameHelper::GenerateNameForNewChildFrame(
168 blink::WebFrame* parent, 151 const std::string& name) const {
169 const std::string& name) { 152 PendingChildFrameAdapter adapter(frame_);
170 return CalculateNewName(parent, nullptr, name); 153 return CalculateNewName(&adapter, name);
171 } 154 }
172 155
173 void UniqueNameHelper::UpdateName(const std::string& name) { 156 void UniqueNameHelper::UpdateName(const std::string& name) {
174 // The unique name of the main frame is always the empty string. 157 // The unique name of the main frame is always the empty string.
175 if (!GetWebFrame()->Parent()) 158 if (frame_->IsMainFrame())
176 return; 159 return;
177 // It's important to clear this before calculating a new name, as the 160 // It's important to clear this before calculating a new name, as the
178 // calculation checks for collisions with existing unique names. 161 // calculation checks for collisions with existing unique names.
179 unique_name_.clear(); 162 unique_name_.clear();
180 unique_name_ = CalculateNewName(GetWebFrame()->Parent(), GetWebFrame(), name); 163 unique_name_ = CalculateNewName(frame_, name);
181 }
182
183 blink::WebLocalFrame* UniqueNameHelper::GetWebFrame() const {
184 return render_frame_->GetWebFrame();
185 } 164 }
186 165
187 } // namespace content 166 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698