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

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: Add comment. Created 3 years, 7 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>
8
9 #include "base/containers/adapters.h"
10 #include "base/logging.h" 7 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h" 9 #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 10
17 namespace content { 11 namespace content {
18 12
19 namespace { 13 namespace {
20 14
21 const std::string& UniqueNameForFrame(blink::WebFrame* frame) { 15 using FrameAdapter = UniqueNameHelper::FrameAdapter;
22 return frame->IsWebLocalFrame() 16
23 ? RenderFrameImpl::FromWebFrame(frame)->unique_name() 17 class PendingChildFrameAdapter : public UniqueNameHelper::FrameAdapter {
24 : RenderFrameProxy::FromWebFrame(frame)->unique_name(); 18 public:
19 explicit PendingChildFrameAdapter(FrameAdapter* parent) : parent_(parent) {}
20
21 // FrameAdapter overrides:
22 bool IsMainFrame() const override { return false; }
23 bool IsCandidateUnique(const std::string& name) const override {
24 return parent_->IsCandidateUnique(name);
25 }
26 int GetSiblingCount() const override { return parent_->GetChildCount(); }
27 int GetChildCount() const override {
28 NOTREACHED();
29 return 0;
30 }
31 std::vector<base::StringPiece> CollectAncestorNames(
32 BeginPoint begin_point,
33 bool (*should_stop)(base::StringPiece)) const override {
34 DCHECK_EQ(BeginPoint::kParentFrame, begin_point);
35 return parent_->CollectAncestorNames(BeginPoint::kThisFrame, should_stop);
36 }
37 std::vector<int> GetFramePosition(BeginPoint begin_point) const override {
38 DCHECK_EQ(BeginPoint::kParentFrame, begin_point);
39 return parent_->GetFramePosition(BeginPoint::kThisFrame);
40 }
41
42 private:
43 FrameAdapter* const parent_;
44 };
45
46 constexpr char kFramePathPrefix[] = "<!--framePath ";
47 constexpr int kFramePathPrefixLength = 14;
48 constexpr int kFramePathSuffixLength = 3;
49
50 bool IsNameWithFramePath(base::StringPiece name) {
51 return name.starts_with(kFramePathPrefix) && name.ends_with("-->") &&
52 (kFramePathPrefixLength + kFramePathSuffixLength) < name.size();
25 } 53 }
26 54
27 bool UniqueNameExists(blink::WebFrame* top, const std::string& candidate) { 55 std::string GenerateCandidate(const FrameAdapter* frame) {
28 // This method is currently O(N), where N = number of frames in the tree. 56 std::string new_name(kFramePathPrefix);
57 new_name += "/";
58 std::vector<base::StringPiece> ancestor_names = frame->CollectAncestorNames(
59 FrameAdapter::BeginPoint::kParentFrame, &IsNameWithFramePath);
60 // Note: This checks ancestor_names[0] twice, but it's nicer to do the name
61 // extraction here rather than passing another function pointer to
62 // CollectAncestorNames().
63 if (!ancestor_names.empty() && IsNameWithFramePath(ancestor_names[0])) {
64 ancestor_names[0] = ancestor_names[0].substr(kFramePathPrefixLength,
65 ancestor_names[0].size() -
66 kFramePathPrefixLength -
67 kFramePathSuffixLength);
68 }
69 new_name += base::JoinString(ancestor_names, "/");
29 70
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"; 71 new_name += "/<!--frame";
79 new_name += base::IntToString(child_count - (child ? 1 : 0)); 72 new_name += base::IntToString(frame->GetSiblingCount());
80 new_name += "-->-->"; 73 new_name += "-->-->";
81 74
82 // NOTE: This name might not be unique - see http://crbug.com/588800. 75 // NOTE: This name might not be unique - see http://crbug.com/588800.
83 return new_name; 76 return new_name;
84 } 77 }
85 78
86 std::string GenerateFramePosition(blink::WebFrame* parent, 79 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"); 80 std::string position_string("<!--framePosition");
91 81 std::vector<int> positions =
92 while (parent) { 82 frame->GetFramePosition(FrameAdapter::BeginPoint::kParentFrame);
93 int position_in_parent = 0; 83 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 += '-'; 84 position_string += '-';
101 position_string += base::IntToString(position_in_parent); 85 position_string += base::IntToString(position);
102
103 child = parent;
104 parent = parent->Parent();
105 } 86 }
106 87
107 // NOTE: The generated string is not guaranteed to be unique, but should 88 // 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 89 // have a better chance of being unique than the string generated by
109 // GenerateCandidate, because we embed extra information into the string: 90 // 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 91 // 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|) 92 // 2) we use frame-position-within-parent (aka |position_in_parent|)
112 // instead of sibling-count. 93 // instead of sibling-count.
113 return position_string; 94 return position_string;
114 } 95 }
115 96
116 std::string AppendUniqueSuffix(blink::WebFrame* top, 97 std::string AppendUniqueSuffix(const FrameAdapter* frame,
117 const std::string& prefix, 98 const std::string& prefix,
118 const std::string& likely_unique_suffix) { 99 const std::string& likely_unique_suffix) {
119 // This should only be called if the |prefix| isn't unique, as this is 100 // This should only be called if the |prefix| isn't unique, as this is
120 // otherwise pointless work. 101 // otherwise pointless work.
121 DCHECK(UniqueNameExists(top, prefix)); 102 DCHECK(!frame->IsCandidateUnique(prefix));
122 103
123 // We want unique name to be stable across page reloads - this is why 104 // 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 105 // 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 106 // (a random number would be more likely to avoid a collision, but
126 // would change after every page reload). 107 // would change after every page reload).
127 int number_of_retries = 0; 108 int number_of_retries = 0;
128 109
129 // Keep trying |prefix| + |likely_unique_suffix| + |number_of_tries| 110 // Keep trying |prefix| + |likely_unique_suffix| + |number_of_tries|
130 // concatenations until we get a truly unique name. 111 // concatenations until we get a truly unique name.
131 std::string candidate(prefix); 112 std::string candidate(prefix);
132 candidate += likely_unique_suffix; 113 candidate += likely_unique_suffix;
133 candidate += '/'; 114 candidate += '/';
134 while (true) { 115 while (true) {
135 size_t current_length = candidate.size(); 116 size_t current_length = candidate.size();
136 candidate += base::IntToString(number_of_retries++); 117 candidate += base::IntToString(number_of_retries++);
137 candidate += "-->"; 118 candidate += "-->";
138 if (!UniqueNameExists(top, candidate)) 119 if (frame->IsCandidateUnique(candidate))
139 break; 120 break;
140 candidate.resize(current_length); 121 candidate.resize(current_length);
141 } 122 }
142 return candidate; 123 return candidate;
143 } 124 }
144 125
145 std::string CalculateNewName(blink::WebFrame* parent, 126 std::string CalculateNewName(const FrameAdapter* frame,
146 blink::WebFrame* child,
147 const std::string& name) { 127 const std::string& name) {
148 blink::WebFrame* top = parent->Top(); 128 if (!name.empty() && frame->IsCandidateUnique(name) && name != "_blank")
149 if (!name.empty() && !UniqueNameExists(top, name) && name != "_blank")
150 return name; 129 return name;
151 130
152 std::string candidate = GenerateCandidate(parent, child); 131 std::string candidate = GenerateCandidate(frame);
153 if (!UniqueNameExists(top, candidate)) 132 if (frame->IsCandidateUnique(candidate))
154 return candidate; 133 return candidate;
155 134
156 std::string likely_unique_suffix = GenerateFramePosition(parent, child); 135 std::string likely_unique_suffix = GenerateFramePosition(frame);
157 return AppendUniqueSuffix(top, candidate, likely_unique_suffix); 136 return AppendUniqueSuffix(frame, candidate, likely_unique_suffix);
158 } 137 }
159 138
160 } // namespace 139 } // namespace
161 140
162 UniqueNameHelper::UniqueNameHelper(RenderFrameImpl* render_frame) 141 UniqueNameHelper::FrameAdapter::~FrameAdapter() {}
163 : render_frame_(render_frame) {} 142
143 UniqueNameHelper::UniqueNameHelper(FrameAdapter* frame) : frame_(frame) {}
164 144
165 UniqueNameHelper::~UniqueNameHelper() {} 145 UniqueNameHelper::~UniqueNameHelper() {}
166 146
167 std::string UniqueNameHelper::GenerateNameForNewChildFrame( 147 std::string UniqueNameHelper::GenerateNameForNewChildFrame(
168 blink::WebFrame* parent, 148 const std::string& name) const {
169 const std::string& name) { 149 PendingChildFrameAdapter adapter(frame_);
170 return CalculateNewName(parent, nullptr, name); 150 return CalculateNewName(&adapter, name);
171 } 151 }
172 152
173 void UniqueNameHelper::UpdateName(const std::string& name) { 153 void UniqueNameHelper::UpdateName(const std::string& name) {
174 // The unique name of the main frame is always the empty string. 154 // The unique name of the main frame is always the empty string.
175 if (!GetWebFrame()->Parent()) 155 if (frame_->IsMainFrame())
176 return; 156 return;
177 // It's important to clear this before calculating a new name, as the 157 // It's important to clear this before calculating a new name, as the
178 // calculation checks for collisions with existing unique names. 158 // calculation checks for collisions with existing unique names.
179 unique_name_.clear(); 159 unique_name_.clear();
Łukasz Anforowicz 2017/05/25 18:33:18 I thought you said (*) that we still need to clear
dcheng 2017/05/25 18:40:41 Doh, forgot to revert the unstaged changes when I
180 unique_name_ = CalculateNewName(GetWebFrame()->Parent(), GetWebFrame(), name); 160 unique_name_ = CalculateNewName(frame_, name);
181 }
182
183 blink::WebLocalFrame* UniqueNameHelper::GetWebFrame() const {
184 return render_frame_->GetWebFrame();
185 } 161 }
186 162
187 } // namespace content 163 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698