OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "bindings/core/v8/ReadableStreamOperations.h" | 5 #include "bindings/core/v8/ReadableStreamOperations.h" |
6 | 6 |
7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
8 #include "bindings/core/v8/ScriptFunction.h" | 8 #include "bindings/core/v8/ScriptFunction.h" |
9 #include "bindings/core/v8/ScriptState.h" | 9 #include "bindings/core/v8/ScriptState.h" |
10 #include "bindings/core/v8/ScriptValue.h" | 10 #include "bindings/core/v8/ScriptValue.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 public: | 52 public: |
53 Iteration() | 53 Iteration() |
54 : m_isSet(false) | 54 : m_isSet(false) |
55 , m_isDone(false) | 55 , m_isDone(false) |
56 , m_isValid(true) {} | 56 , m_isValid(true) {} |
57 | 57 |
58 void set(ScriptValue v) | 58 void set(ScriptValue v) |
59 { | 59 { |
60 ASSERT(!v.isEmpty()); | 60 ASSERT(!v.isEmpty()); |
61 m_isSet = true; | 61 m_isSet = true; |
62 v8::TryCatch block(v.scriptState()->isolate()); | 62 v8::TryCatch block(v.getScriptState()->isolate()); |
63 v8::Local<v8::Value> value; | 63 v8::Local<v8::Value> value; |
64 v8::Local<v8::Value> item = v.v8Value(); | 64 v8::Local<v8::Value> item = v.v8Value(); |
65 if (!item->IsObject() || !v8Call(v8UnpackIteratorResult(v.scriptState(),
item.As<v8::Object>(), &m_isDone), value)) { | 65 if (!item->IsObject() || !v8Call(v8UnpackIteratorResult(v.getScriptState
(), item.As<v8::Object>(), &m_isDone), value)) { |
66 m_isValid = false; | 66 m_isValid = false; |
67 return; | 67 return; |
68 } | 68 } |
69 m_value = toCoreString(value->ToString()); | 69 m_value = toCoreString(value->ToString()); |
70 } | 70 } |
71 | 71 |
72 bool isSet() const { return m_isSet; } | 72 bool isSet() const { return m_isSet; } |
73 bool isDone() const { return m_isDone; } | 73 bool isDone() const { return m_isDone; } |
74 bool isValid() const { return m_isValid; } | 74 bool isValid() const { return m_isValid; } |
75 const String& value() const { return m_value; } | 75 const String& value() const { return m_value; } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 double desiredSize() { return controller()->desiredSize(); } | 127 double desiredSize() { return controller()->desiredSize(); } |
128 }; | 128 }; |
129 | 129 |
130 class ReadableStreamOperationsTest : public ::testing::Test { | 130 class ReadableStreamOperationsTest : public ::testing::Test { |
131 public: | 131 public: |
132 ReadableStreamOperationsTest() | 132 ReadableStreamOperationsTest() |
133 : m_scope(v8::Isolate::GetCurrent()) | 133 : m_scope(v8::Isolate::GetCurrent()) |
134 , m_block(isolate()) | 134 , m_block(isolate()) |
135 , m_document(Document::create()) | 135 , m_document(Document::create()) |
136 { | 136 { |
137 scriptState()->setExecutionContext(m_document.get()); | 137 getScriptState()->setExecutionContext(m_document.get()); |
138 } | 138 } |
139 ~ReadableStreamOperationsTest() override | 139 ~ReadableStreamOperationsTest() override |
140 { | 140 { |
141 // Execute all pending microtasks | 141 // Execute all pending microtasks |
142 v8::MicrotasksScope::PerformCheckpoint(isolate()); | 142 v8::MicrotasksScope::PerformCheckpoint(isolate()); |
143 EXPECT_FALSE(m_block.HasCaught()); | 143 EXPECT_FALSE(m_block.HasCaught()); |
144 } | 144 } |
145 | 145 |
146 ScriptState* scriptState() const { return m_scope.scriptState(); } | 146 ScriptState* getScriptState() const { return m_scope.getScriptState(); } |
147 v8::Isolate* isolate() const { return scriptState()->isolate(); } | 147 v8::Isolate* isolate() const { return getScriptState()->isolate(); } |
148 | 148 |
149 ScriptValue eval(const char* s) | 149 ScriptValue eval(const char* s) |
150 { | 150 { |
151 v8::Local<v8::String> source; | 151 v8::Local<v8::String> source; |
152 v8::Local<v8::Script> script; | 152 v8::Local<v8::Script> script; |
153 V8RecursionScope::MicrotaskSuppression microtasks(isolate()); | 153 V8RecursionScope::MicrotaskSuppression microtasks(isolate()); |
154 if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNo
rmal), source)) { | 154 if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNo
rmal), source)) { |
155 ADD_FAILURE(); | 155 ADD_FAILURE(); |
156 return ScriptValue(); | 156 return ScriptValue(); |
157 } | 157 } |
158 if (!v8Call(v8::Script::Compile(scriptState()->context(), source), scrip
t)) { | 158 if (!v8Call(v8::Script::Compile(getScriptState()->context(), source), sc
ript)) { |
159 ADD_FAILURE() << "Compilation fails"; | 159 ADD_FAILURE() << "Compilation fails"; |
160 return ScriptValue(); | 160 return ScriptValue(); |
161 } | 161 } |
162 return ScriptValue(scriptState(), script->Run(scriptState()->context()))
; | 162 return ScriptValue(getScriptState(), script->Run(getScriptState()->conte
xt())); |
163 } | 163 } |
164 ScriptValue evalWithPrintingError(const char* s) | 164 ScriptValue evalWithPrintingError(const char* s) |
165 { | 165 { |
166 v8::TryCatch block(isolate()); | 166 v8::TryCatch block(isolate()); |
167 ScriptValue r = eval(s); | 167 ScriptValue r = eval(s); |
168 if (block.HasCaught()) { | 168 if (block.HasCaught()) { |
169 ADD_FAILURE() << toCoreString(block.Exception()->ToString(isolate())
).utf8().data(); | 169 ADD_FAILURE() << toCoreString(block.Exception()->ToString(isolate())
).utf8().data(); |
170 block.ReThrow(); | 170 block.ReThrow(); |
171 } | 171 } |
172 return r; | 172 return r; |
173 } | 173 } |
174 | 174 |
175 V8TestingScope m_scope; | 175 V8TestingScope m_scope; |
176 v8::TryCatch m_block; | 176 v8::TryCatch m_block; |
177 RefPtrWillBePersistent<Document> m_document; | 177 RefPtrWillBePersistent<Document> m_document; |
178 }; | 178 }; |
179 | 179 |
180 TEST_F(ReadableStreamOperationsTest, IsReadableStream) | 180 TEST_F(ReadableStreamOperationsTest, IsReadableStream) |
181 { | 181 { |
182 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), Scrip
tValue(scriptState(), v8::Undefined(isolate())))); | 182 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(getScriptState(), Sc
riptValue(getScriptState(), v8::Undefined(isolate())))); |
183 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), Scrip
tValue::createNull(scriptState()))); | 183 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(getScriptState(), Sc
riptValue::createNull(getScriptState()))); |
184 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), Scrip
tValue(scriptState(), v8::Object::New(isolate())))); | 184 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(getScriptState(), Sc
riptValue(getScriptState(), v8::Object::New(isolate())))); |
185 ScriptValue stream = evalWithPrintingError("new ReadableStream()"); | 185 ScriptValue stream = evalWithPrintingError("new ReadableStream()"); |
186 EXPECT_FALSE(stream.isEmpty()); | 186 EXPECT_FALSE(stream.isEmpty()); |
187 EXPECT_TRUE(ReadableStreamOperations::isReadableStream(scriptState(), stream
)); | 187 EXPECT_TRUE(ReadableStreamOperations::isReadableStream(getScriptState(), str
eam)); |
188 } | 188 } |
189 | 189 |
190 TEST_F(ReadableStreamOperationsTest, IsReadableStreamReaderInvalid) | 190 TEST_F(ReadableStreamOperationsTest, IsReadableStreamReaderInvalid) |
191 { | 191 { |
192 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
ScriptValue(scriptState(), v8::Undefined(isolate())))); | 192 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(getScriptState
(), ScriptValue(getScriptState(), v8::Undefined(isolate())))); |
193 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
ScriptValue::createNull(scriptState()))); | 193 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(getScriptState
(), ScriptValue::createNull(getScriptState()))); |
194 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
ScriptValue(scriptState(), v8::Object::New(isolate())))); | 194 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(getScriptState
(), ScriptValue(getScriptState(), v8::Object::New(isolate())))); |
195 ScriptValue stream = evalWithPrintingError("new ReadableStream()"); | 195 ScriptValue stream = evalWithPrintingError("new ReadableStream()"); |
196 EXPECT_FALSE(stream.isEmpty()); | 196 EXPECT_FALSE(stream.isEmpty()); |
197 | 197 |
198 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
stream)); | 198 EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(getScriptState
(), stream)); |
199 } | 199 } |
200 | 200 |
201 TEST_F(ReadableStreamOperationsTest, GetReader) | 201 TEST_F(ReadableStreamOperationsTest, GetReader) |
202 { | 202 { |
203 ScriptValue stream = evalWithPrintingError("new ReadableStream()"); | 203 ScriptValue stream = evalWithPrintingError("new ReadableStream()"); |
204 EXPECT_FALSE(stream.isEmpty()); | 204 EXPECT_FALSE(stream.isEmpty()); |
205 | 205 |
206 EXPECT_FALSE(ReadableStreamOperations::isLocked(scriptState(), stream)); | 206 EXPECT_FALSE(ReadableStreamOperations::isLocked(getScriptState(), stream)); |
207 ScriptValue reader; | 207 ScriptValue reader; |
208 { | 208 { |
209 TrackExceptionState es; | 209 TrackExceptionState es; |
210 reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 210 reader = ReadableStreamOperations::getReader(getScriptState(), stream, e
s); |
211 ASSERT_FALSE(es.hadException()); | 211 ASSERT_FALSE(es.hadException()); |
212 } | 212 } |
213 EXPECT_TRUE(ReadableStreamOperations::isLocked(scriptState(), stream)); | 213 EXPECT_TRUE(ReadableStreamOperations::isLocked(getScriptState(), stream)); |
214 ASSERT_FALSE(reader.isEmpty()); | 214 ASSERT_FALSE(reader.isEmpty()); |
215 | 215 |
216 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), reade
r)); | 216 EXPECT_FALSE(ReadableStreamOperations::isReadableStream(getScriptState(), re
ader)); |
217 EXPECT_TRUE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
reader)); | 217 EXPECT_TRUE(ReadableStreamOperations::isReadableStreamReader(getScriptState(
), reader)); |
218 | 218 |
219 // Already locked! | 219 // Already locked! |
220 { | 220 { |
221 TrackExceptionState es; | 221 TrackExceptionState es; |
222 reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 222 reader = ReadableStreamOperations::getReader(getScriptState(), stream, e
s); |
223 ASSERT_TRUE(es.hadException()); | 223 ASSERT_TRUE(es.hadException()); |
224 } | 224 } |
225 ASSERT_TRUE(reader.isEmpty()); | 225 ASSERT_TRUE(reader.isEmpty()); |
226 } | 226 } |
227 | 227 |
228 TEST_F(ReadableStreamOperationsTest, IsDisturbed) | 228 TEST_F(ReadableStreamOperationsTest, IsDisturbed) |
229 { | 229 { |
230 ScriptValue stream = evalWithPrintingError("stream = new ReadableStream()"); | 230 ScriptValue stream = evalWithPrintingError("stream = new ReadableStream()"); |
231 EXPECT_FALSE(stream.isEmpty()); | 231 EXPECT_FALSE(stream.isEmpty()); |
232 | 232 |
233 EXPECT_FALSE(ReadableStreamOperations::isDisturbed(scriptState(), stream)); | 233 EXPECT_FALSE(ReadableStreamOperations::isDisturbed(getScriptState(), stream)
); |
234 | 234 |
235 ASSERT_FALSE(evalWithPrintingError("stream.cancel()").isEmpty()); | 235 ASSERT_FALSE(evalWithPrintingError("stream.cancel()").isEmpty()); |
236 | 236 |
237 EXPECT_TRUE(ReadableStreamOperations::isDisturbed(scriptState(), stream)); | 237 EXPECT_TRUE(ReadableStreamOperations::isDisturbed(getScriptState(), stream))
; |
238 } | 238 } |
239 | 239 |
240 TEST_F(ReadableStreamOperationsTest, Read) | 240 TEST_F(ReadableStreamOperationsTest, Read) |
241 { | 241 { |
242 ScriptValue reader = evalWithPrintingError( | 242 ScriptValue reader = evalWithPrintingError( |
243 "var controller;" | 243 "var controller;" |
244 "function start(c) { controller = c; }" | 244 "function start(c) { controller = c; }" |
245 "new ReadableStream({start}).getReader()"); | 245 "new ReadableStream({start}).getReader()"); |
246 EXPECT_FALSE(reader.isEmpty()); | 246 EXPECT_FALSE(reader.isEmpty()); |
247 ASSERT_TRUE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
reader)); | 247 ASSERT_TRUE(ReadableStreamOperations::isReadableStreamReader(getScriptState(
), reader)); |
248 | 248 |
249 Iteration* it1 = new Iteration(); | 249 Iteration* it1 = new Iteration(); |
250 Iteration* it2 = new Iteration(); | 250 Iteration* it2 = new Iteration(); |
251 ReadableStreamOperations::read(scriptState(), reader).then( | 251 ReadableStreamOperations::read(getScriptState(), reader).then( |
252 Function::createFunction(scriptState(), it1), | 252 Function::createFunction(getScriptState(), it1), |
253 NotReached::createFunction(scriptState())); | 253 NotReached::createFunction(getScriptState())); |
254 ReadableStreamOperations::read(scriptState(), reader).then( | 254 ReadableStreamOperations::read(getScriptState(), reader).then( |
255 Function::createFunction(scriptState(), it2), | 255 Function::createFunction(getScriptState(), it2), |
256 NotReached::createFunction(scriptState())); | 256 NotReached::createFunction(getScriptState())); |
257 | 257 |
258 v8::MicrotasksScope::PerformCheckpoint(isolate()); | 258 v8::MicrotasksScope::PerformCheckpoint(isolate()); |
259 EXPECT_FALSE(it1->isSet()); | 259 EXPECT_FALSE(it1->isSet()); |
260 EXPECT_FALSE(it2->isSet()); | 260 EXPECT_FALSE(it2->isSet()); |
261 | 261 |
262 ASSERT_FALSE(evalWithPrintingError("controller.enqueue('hello')").isEmpty())
; | 262 ASSERT_FALSE(evalWithPrintingError("controller.enqueue('hello')").isEmpty())
; |
263 v8::MicrotasksScope::PerformCheckpoint(isolate()); | 263 v8::MicrotasksScope::PerformCheckpoint(isolate()); |
264 EXPECT_TRUE(it1->isSet()); | 264 EXPECT_TRUE(it1->isSet()); |
265 EXPECT_TRUE(it1->isValid()); | 265 EXPECT_TRUE(it1->isValid()); |
266 EXPECT_FALSE(it1->isDone()); | 266 EXPECT_FALSE(it1->isDone()); |
267 EXPECT_EQ("hello", it1->value()); | 267 EXPECT_EQ("hello", it1->value()); |
268 EXPECT_FALSE(it2->isSet()); | 268 EXPECT_FALSE(it2->isSet()); |
269 | 269 |
270 ASSERT_FALSE(evalWithPrintingError("controller.close()").isEmpty()); | 270 ASSERT_FALSE(evalWithPrintingError("controller.close()").isEmpty()); |
271 v8::MicrotasksScope::PerformCheckpoint(isolate()); | 271 v8::MicrotasksScope::PerformCheckpoint(isolate()); |
272 EXPECT_TRUE(it1->isSet()); | 272 EXPECT_TRUE(it1->isSet()); |
273 EXPECT_TRUE(it1->isValid()); | 273 EXPECT_TRUE(it1->isValid()); |
274 EXPECT_FALSE(it1->isDone()); | 274 EXPECT_FALSE(it1->isDone()); |
275 EXPECT_EQ("hello", it1->value()); | 275 EXPECT_EQ("hello", it1->value()); |
276 EXPECT_TRUE(it2->isSet()); | 276 EXPECT_TRUE(it2->isSet()); |
277 EXPECT_TRUE(it2->isValid()); | 277 EXPECT_TRUE(it2->isValid()); |
278 EXPECT_TRUE(it2->isDone()); | 278 EXPECT_TRUE(it2->isDone()); |
279 } | 279 } |
280 | 280 |
281 TEST_F(ReadableStreamOperationsTest, CreateReadableStreamWithCustomUnderlyingSou
rceAndStrategy) | 281 TEST_F(ReadableStreamOperationsTest, CreateReadableStreamWithCustomUnderlyingSou
rceAndStrategy) |
282 { | 282 { |
283 auto underlyingSource = new TestUnderlyingSource(scriptState()); | 283 auto underlyingSource = new TestUnderlyingSource(getScriptState()); |
284 | 284 |
285 ScriptValue strategy = ReadableStreamOperations::createCountQueuingStrategy(
scriptState(), 10); | 285 ScriptValue strategy = ReadableStreamOperations::createCountQueuingStrategy(
getScriptState(), 10); |
286 ASSERT_FALSE(strategy.isEmpty()); | 286 ASSERT_FALSE(strategy.isEmpty()); |
287 | 287 |
288 ScriptValue stream = ReadableStreamOperations::createReadableStream(scriptSt
ate(), underlyingSource, strategy); | 288 ScriptValue stream = ReadableStreamOperations::createReadableStream(getScrip
tState(), underlyingSource, strategy); |
289 ASSERT_FALSE(stream.isEmpty()); | 289 ASSERT_FALSE(stream.isEmpty()); |
290 | 290 |
291 EXPECT_EQ(10, underlyingSource->desiredSize()); | 291 EXPECT_EQ(10, underlyingSource->desiredSize()); |
292 | 292 |
293 underlyingSource->enqueue(ScriptValue::from(scriptState(), "a")); | 293 underlyingSource->enqueue(ScriptValue::from(getScriptState(), "a")); |
294 EXPECT_EQ(9, underlyingSource->desiredSize()); | 294 EXPECT_EQ(9, underlyingSource->desiredSize()); |
295 | 295 |
296 underlyingSource->enqueue(ScriptValue::from(scriptState(), "b")); | 296 underlyingSource->enqueue(ScriptValue::from(getScriptState(), "b")); |
297 EXPECT_EQ(8, underlyingSource->desiredSize()); | 297 EXPECT_EQ(8, underlyingSource->desiredSize()); |
298 | 298 |
299 ScriptValue reader; | 299 ScriptValue reader; |
300 { | 300 { |
301 TrackExceptionState es; | 301 TrackExceptionState es; |
302 reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 302 reader = ReadableStreamOperations::getReader(getScriptState(), stream, e
s); |
303 ASSERT_FALSE(es.hadException()); | 303 ASSERT_FALSE(es.hadException()); |
304 } | 304 } |
305 ASSERT_FALSE(reader.isEmpty()); | 305 ASSERT_FALSE(reader.isEmpty()); |
306 | 306 |
307 Iteration* it1 = new Iteration(); | 307 Iteration* it1 = new Iteration(); |
308 Iteration* it2 = new Iteration(); | 308 Iteration* it2 = new Iteration(); |
309 Iteration* it3 = new Iteration(); | 309 Iteration* it3 = new Iteration(); |
310 ReadableStreamOperations::read(scriptState(), reader).then(Function::createF
unction(scriptState(), it1), NotReached::createFunction(scriptState())); | 310 ReadableStreamOperations::read(getScriptState(), reader).then(Function::crea
teFunction(getScriptState(), it1), NotReached::createFunction(getScriptState()))
; |
311 ReadableStreamOperations::read(scriptState(), reader).then(Function::createF
unction(scriptState(), it2), NotReached::createFunction(scriptState())); | 311 ReadableStreamOperations::read(getScriptState(), reader).then(Function::crea
teFunction(getScriptState(), it2), NotReached::createFunction(getScriptState()))
; |
312 ReadableStreamOperations::read(scriptState(), reader).then(Function::createF
unction(scriptState(), it3), NotReached::createFunction(scriptState())); | 312 ReadableStreamOperations::read(getScriptState(), reader).then(Function::crea
teFunction(getScriptState(), it3), NotReached::createFunction(getScriptState()))
; |
313 | 313 |
314 v8::MicrotasksScope::PerformCheckpoint(isolate()); | 314 v8::MicrotasksScope::PerformCheckpoint(isolate()); |
315 | 315 |
316 EXPECT_EQ(10, underlyingSource->desiredSize()); | 316 EXPECT_EQ(10, underlyingSource->desiredSize()); |
317 | 317 |
318 EXPECT_TRUE(it1->isSet()); | 318 EXPECT_TRUE(it1->isSet()); |
319 EXPECT_TRUE(it1->isValid()); | 319 EXPECT_TRUE(it1->isValid()); |
320 EXPECT_FALSE(it1->isDone()); | 320 EXPECT_FALSE(it1->isDone()); |
321 EXPECT_EQ("a", it1->value()); | 321 EXPECT_EQ("a", it1->value()); |
322 | 322 |
323 EXPECT_TRUE(it2->isSet()); | 323 EXPECT_TRUE(it2->isSet()); |
324 EXPECT_TRUE(it2->isValid()); | 324 EXPECT_TRUE(it2->isValid()); |
325 EXPECT_FALSE(it2->isDone()); | 325 EXPECT_FALSE(it2->isDone()); |
326 EXPECT_EQ("b", it2->value()); | 326 EXPECT_EQ("b", it2->value()); |
327 | 327 |
328 EXPECT_FALSE(it3->isSet()); | 328 EXPECT_FALSE(it3->isSet()); |
329 | 329 |
330 underlyingSource->close(); | 330 underlyingSource->close(); |
331 v8::MicrotasksScope::PerformCheckpoint(isolate()); | 331 v8::MicrotasksScope::PerformCheckpoint(isolate()); |
332 | 332 |
333 EXPECT_TRUE(it3->isSet()); | 333 EXPECT_TRUE(it3->isSet()); |
334 EXPECT_TRUE(it3->isValid()); | 334 EXPECT_TRUE(it3->isValid()); |
335 EXPECT_TRUE(it3->isDone()); | 335 EXPECT_TRUE(it3->isDone()); |
336 } | 336 } |
337 | 337 |
338 } // namespace | 338 } // namespace |
339 | 339 |
340 } // namespace blink | 340 } // namespace blink |
341 | 341 |
OLD | NEW |