| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/gpu/gpu_benchmarking_extension.h" | 5 #include "content/renderer/gpu/gpu_benchmarking_extension.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 | 207 |
| 208 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext); | 208 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext); |
| 209 }; | 209 }; |
| 210 | 210 |
| 211 } // namespace | 211 } // namespace |
| 212 | 212 |
| 213 class GpuBenchmarkingWrapper : public v8::Extension { | 213 class GpuBenchmarkingWrapper : public v8::Extension { |
| 214 public: | 214 public: |
| 215 GpuBenchmarkingWrapper() : | 215 GpuBenchmarkingWrapper() : |
| 216 v8::Extension(kGpuBenchmarkingExtensionName, | 216 v8::Extension(kGpuBenchmarkingExtensionName, |
| 217 "if (typeof(chrome) == 'undefined') {" | 217 "if (typeof(chrome) == 'undefined') {" |
| 218 " chrome = {};" | 218 " chrome = {};" |
| 219 "};" | 219 "};" |
| 220 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {" | 220 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {" |
| 221 " chrome.gpuBenchmarking = {};" | 221 " chrome.gpuBenchmarking = {};" |
| 222 "};" | 222 "};" |
| 223 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {" | 223 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {" |
| 224 " native function SetNeedsDisplayOnAllLayers();" | 224 " native function SetNeedsDisplayOnAllLayers();" |
| 225 " return SetNeedsDisplayOnAllLayers();" | 225 " return SetNeedsDisplayOnAllLayers();" |
| 226 "};" | 226 "};" |
| 227 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = function() {" | 227 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = " |
| 228 " native function SetRasterizeOnlyVisibleContent();" | 228 "function() {" |
| 229 " return SetRasterizeOnlyVisibleContent();" | 229 " native function SetRasterizeOnlyVisibleContent();" |
| 230 "};" | 230 " return SetRasterizeOnlyVisibleContent();" |
| 231 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {" | 231 "};" |
| 232 " native function PrintToSkPicture();" | 232 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {" |
| 233 " return PrintToSkPicture(dirname);" | 233 " native function PrintToSkPicture();" |
| 234 "};" | 234 " return PrintToSkPicture(dirname);" |
| 235 "chrome.gpuBenchmarking.DEFAULT_INPUT = 0;" | 235 "};" |
| 236 "chrome.gpuBenchmarking.TOUCH_INPUT = 1;" | 236 "chrome.gpuBenchmarking.DEFAULT_INPUT = 0;" |
| 237 "chrome.gpuBenchmarking.MOUSE_INPUT = 2;" | 237 "chrome.gpuBenchmarking.TOUCH_INPUT = 1;" |
| 238 "chrome.gpuBenchmarking.gestureSourceTypeSupported = " | 238 "chrome.gpuBenchmarking.MOUSE_INPUT = 2;" |
| 239 " function(gesture_source_type) {" | 239 "chrome.gpuBenchmarking.gestureSourceTypeSupported = " |
| 240 " native function GestureSourceTypeSupported();" | 240 " function(gesture_source_type) {" |
| 241 " return GestureSourceTypeSupported(gesture_source_type);" | 241 " native function GestureSourceTypeSupported();" |
| 242 "};" | 242 " return GestureSourceTypeSupported(gesture_source_type);" |
| 243 "chrome.gpuBenchmarking.smoothScrollBy = " | 243 "};" |
| 244 " function(pixels_to_scroll, opt_callback, opt_start_x," | 244 "chrome.gpuBenchmarking.smoothScrollBy = " |
| 245 " opt_start_y, opt_gesture_source_type," | 245 " function(pixels_to_scroll, opt_callback, opt_start_x," |
| 246 " opt_direction, opt_speed_in_pixels_s) {" | 246 " opt_start_y, opt_gesture_source_type," |
| 247 " pixels_to_scroll = pixels_to_scroll || 0;" | 247 " opt_direction, opt_speed_in_pixels_s) {" |
| 248 " callback = opt_callback || function() { };" | 248 " pixels_to_scroll = pixels_to_scroll || 0;" |
| 249 " gesture_source_type = opt_gesture_source_type ||" | 249 " callback = opt_callback || function() { };" |
| 250 " chrome.gpuBenchmarking.DEFAULT_INPUT;" | 250 " gesture_source_type = opt_gesture_source_type ||" |
| 251 " direction = opt_direction || 'down';" | 251 " chrome.gpuBenchmarking.DEFAULT_INPUT;" |
| 252 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" | 252 " direction = opt_direction || 'down';" |
| 253 " native function BeginSmoothScroll();" | 253 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" |
| 254 " return BeginSmoothScroll(pixels_to_scroll, callback," | 254 " native function BeginSmoothScroll();" |
| 255 " gesture_source_type, direction," | 255 " return BeginSmoothScroll(pixels_to_scroll, callback," |
| 256 " speed_in_pixels_s, true," | 256 " gesture_source_type, direction," |
| 257 " opt_start_x, opt_start_y);" | 257 " speed_in_pixels_s, true," |
| 258 "};" | 258 " opt_start_x, opt_start_y);" |
| 259 "chrome.gpuBenchmarking.swipe = " | 259 "};" |
| 260 " function(direction, distance, opt_callback," | 260 "chrome.gpuBenchmarking.swipe = " |
| 261 " opt_start_x, opt_start_y," | 261 " function(direction, distance, opt_callback," |
| 262 " opt_speed_in_pixels_s) {" | 262 " opt_start_x, opt_start_y," |
| 263 " direction = direction || 'up';" | 263 " opt_speed_in_pixels_s) {" |
| 264 " distance = distance || 0;" | 264 " direction = direction || 'up';" |
| 265 " callback = opt_callback || function() { };" | 265 " distance = distance || 0;" |
| 266 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" | 266 " callback = opt_callback || function() { };" |
| 267 " native function BeginSmoothScroll();" | 267 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" |
| 268 " return BeginSmoothScroll(-distance, callback," | 268 " native function BeginSmoothScroll();" |
| 269 " chrome.gpuBenchmarking.TOUCH_INPUT," | 269 " return BeginSmoothScroll(-distance, callback," |
| 270 " direction, speed_in_pixels_s, false," | 270 " chrome.gpuBenchmarking.TOUCH_INPUT," |
| 271 " opt_start_x, opt_start_y);" | 271 " direction, speed_in_pixels_s, false," |
| 272 "};" | 272 " opt_start_x, opt_start_y);" |
| 273 "chrome.gpuBenchmarking.scrollBounce = " | 273 "};" |
| 274 " function(direction, distance, overscroll, opt_repeat_count," | 274 "chrome.gpuBenchmarking.scrollBounce = " |
| 275 " opt_callback, opt_start_x, opt_start_y," | 275 " function(direction, distance, overscroll, opt_repeat_count," |
| 276 " opt_speed_in_pixels_s) {" | 276 " opt_callback, opt_start_x, opt_start_y," |
| 277 " direction = direction || 'down';" | 277 " opt_speed_in_pixels_s) {" |
| 278 " distance = distance || 0;" | 278 " direction = direction || 'down';" |
| 279 " overscroll = overscroll || 0;" | 279 " distance = distance || 0;" |
| 280 " repeat_count = opt_repeat_count || 1;" | 280 " overscroll = overscroll || 0;" |
| 281 " callback = opt_callback || function() { };" | 281 " repeat_count = opt_repeat_count || 1;" |
| 282 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" | 282 " callback = opt_callback || function() { };" |
| 283 " native function BeginScrollBounce();" | 283 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" |
| 284 " return BeginScrollBounce(direction, distance, overscroll," | 284 " native function BeginScrollBounce();" |
| 285 " repeat_count, callback," | 285 " return BeginScrollBounce(direction, distance, overscroll," |
| 286 " speed_in_pixels_s," | 286 " repeat_count, callback," |
| 287 " opt_start_x, opt_start_y);" | 287 " speed_in_pixels_s," |
| 288 "};" | 288 " opt_start_x, opt_start_y);" |
| 289 // TODO(dominikg): Remove once JS interface changes have rolled into | 289 "};" |
| 290 // stable. | 290 // TODO(dominikg): Remove once JS interface changes have rolled into |
| 291 "chrome.gpuBenchmarking.newPinchInterface = true;" | 291 // stable. |
| 292 "chrome.gpuBenchmarking.pinchBy = " | 292 "chrome.gpuBenchmarking.newPinchInterface = true;" |
| 293 " function(scale_factor, anchor_x, anchor_y," | 293 "chrome.gpuBenchmarking.pinchBy = " |
| 294 " opt_callback, opt_relative_pointer_speed_in_pixels_s) {" | 294 " function(scale_factor, anchor_x, anchor_y," |
| 295 " callback = opt_callback || function() { };" | 295 " opt_callback, " |
| 296 " relative_pointer_speed_in_pixels_s =" | 296 "opt_relative_pointer_speed_in_pixels_s) {" |
| 297 " opt_relative_pointer_speed_in_pixels_s || 800;" | 297 " callback = opt_callback || function() { };" |
| 298 " native function BeginPinch();" | 298 " relative_pointer_speed_in_pixels_s =" |
| 299 " return BeginPinch(scale_factor, anchor_x, anchor_y, callback," | 299 " opt_relative_pointer_speed_in_pixels_s || 800;" |
| 300 " relative_pointer_speed_in_pixels_s);" | 300 " native function BeginPinch();" |
| 301 "};" | 301 " return BeginPinch(scale_factor, anchor_x, anchor_y, callback," |
| 302 "chrome.gpuBenchmarking.tap = " | 302 " relative_pointer_speed_in_pixels_s);" |
| 303 " function(position_x, position_y, opt_callback, opt_duration_ms," | 303 "};" |
| 304 " opt_gesture_source_type) {" | 304 "chrome.gpuBenchmarking.tap = " |
| 305 " callback = opt_callback || function() { };" | 305 " function(position_x, position_y, opt_callback, " |
| 306 " duration_ms = opt_duration_ms || 50;" | 306 "opt_duration_ms," |
| 307 " gesture_source_type = opt_gesture_source_type ||" | 307 " opt_gesture_source_type) {" |
| 308 " chrome.gpuBenchmarking.DEFAULT_INPUT;" | 308 " callback = opt_callback || function() { };" |
| 309 " native function BeginTap();" | 309 " duration_ms = opt_duration_ms || 50;" |
| 310 " return BeginTap(position_x, position_y, callback, duration_ms," | 310 " gesture_source_type = opt_gesture_source_type ||" |
| 311 " gesture_source_type);" | 311 " chrome.gpuBenchmarking.DEFAULT_INPUT;" |
| 312 "};" | 312 " native function BeginTap();" |
| 313 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = function(callback) {" | 313 " return BeginTap(position_x, position_y, callback, duration_ms," |
| 314 " native function BeginWindowSnapshotPNG();" | 314 " gesture_source_type);" |
| 315 " BeginWindowSnapshotPNG(callback);" | 315 "};" |
| 316 "};" | 316 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = " |
| 317 "chrome.gpuBenchmarking.clearImageCache = function() {" | 317 "function(callback) {" |
| 318 " native function ClearImageCache();" | 318 " native function BeginWindowSnapshotPNG();" |
| 319 " ClearImageCache();" | 319 " BeginWindowSnapshotPNG(callback);" |
| 320 "};" | 320 "};" |
| 321 "chrome.gpuBenchmarking.runMicroBenchmark =" | 321 "chrome.gpuBenchmarking.clearImageCache = function() {" |
| 322 " function(name, callback, opt_arguments) {" | 322 " native function ClearImageCache();" |
| 323 " arguments = opt_arguments || {};" | 323 " ClearImageCache();" |
| 324 " native function RunMicroBenchmark();" | 324 "};" |
| 325 " return RunMicroBenchmark(name, callback, arguments);" | 325 "chrome.gpuBenchmarking.runMicroBenchmark =" |
| 326 "};" | 326 " function(name, callback, opt_arguments) {" |
| 327 "chrome.gpuBenchmarking.hasGpuProcess = function() {" | 327 " arguments = opt_arguments || {};" |
| 328 " native function HasGpuProcess();" | 328 " native function RunMicroBenchmark();" |
| 329 " return HasGpuProcess();" | 329 " return RunMicroBenchmark(name, callback, arguments);" |
| 330 "};") {} | 330 "};" |
| 331 "chrome.gpuBenchmarking.sendMessageToMicroBenchmark =" |
| 332 " function(id, arguments) {" |
| 333 " native function SendMessageToMicroBenchmark();" |
| 334 " return SendMessageToMicroBenchmark(id, arguments);" |
| 335 "};" |
| 336 "chrome.gpuBenchmarking.hasGpuProcess = function() {" |
| 337 " native function HasGpuProcess();" |
| 338 " return HasGpuProcess();" |
| 339 "};") {} |
| 331 | 340 |
| 332 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( | 341 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( |
| 333 v8::Isolate* isolate, | 342 v8::Isolate* isolate, |
| 334 v8::Handle<v8::String> name) OVERRIDE { | 343 v8::Handle<v8::String> name) OVERRIDE { |
| 335 if (name->Equals( | 344 if (name->Equals( |
| 336 v8::String::NewFromUtf8(isolate, "SetNeedsDisplayOnAllLayers"))) | 345 v8::String::NewFromUtf8(isolate, "SetNeedsDisplayOnAllLayers"))) |
| 337 return v8::FunctionTemplate::New(isolate, SetNeedsDisplayOnAllLayers); | 346 return v8::FunctionTemplate::New(isolate, SetNeedsDisplayOnAllLayers); |
| 338 if (name->Equals( | 347 if (name->Equals( |
| 339 v8::String::NewFromUtf8(isolate, "SetRasterizeOnlyVisibleContent"))) | 348 v8::String::NewFromUtf8(isolate, "SetRasterizeOnlyVisibleContent"))) |
| 340 return v8::FunctionTemplate::New(isolate, SetRasterizeOnlyVisibleContent); | 349 return v8::FunctionTemplate::New(isolate, SetRasterizeOnlyVisibleContent); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 351 return v8::FunctionTemplate::New(isolate, BeginPinch); | 360 return v8::FunctionTemplate::New(isolate, BeginPinch); |
| 352 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginTap"))) | 361 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginTap"))) |
| 353 return v8::FunctionTemplate::New(isolate, BeginTap); | 362 return v8::FunctionTemplate::New(isolate, BeginTap); |
| 354 if (name->Equals( | 363 if (name->Equals( |
| 355 v8::String::NewFromUtf8(isolate, "BeginWindowSnapshotPNG"))) | 364 v8::String::NewFromUtf8(isolate, "BeginWindowSnapshotPNG"))) |
| 356 return v8::FunctionTemplate::New(isolate, BeginWindowSnapshotPNG); | 365 return v8::FunctionTemplate::New(isolate, BeginWindowSnapshotPNG); |
| 357 if (name->Equals(v8::String::NewFromUtf8(isolate, "ClearImageCache"))) | 366 if (name->Equals(v8::String::NewFromUtf8(isolate, "ClearImageCache"))) |
| 358 return v8::FunctionTemplate::New(isolate, ClearImageCache); | 367 return v8::FunctionTemplate::New(isolate, ClearImageCache); |
| 359 if (name->Equals(v8::String::NewFromUtf8(isolate, "RunMicroBenchmark"))) | 368 if (name->Equals(v8::String::NewFromUtf8(isolate, "RunMicroBenchmark"))) |
| 360 return v8::FunctionTemplate::New(isolate, RunMicroBenchmark); | 369 return v8::FunctionTemplate::New(isolate, RunMicroBenchmark); |
| 370 if (name->Equals( |
| 371 v8::String::NewFromUtf8(isolate, "SendMessageToMicroBenchmark"))) |
| 372 return v8::FunctionTemplate::New(isolate, SendMessageToMicroBenchmark); |
| 361 if (name->Equals(v8::String::NewFromUtf8(isolate, "HasGpuProcess"))) | 373 if (name->Equals(v8::String::NewFromUtf8(isolate, "HasGpuProcess"))) |
| 362 return v8::FunctionTemplate::New(isolate, HasGpuProcess); | 374 return v8::FunctionTemplate::New(isolate, HasGpuProcess); |
| 363 | 375 |
| 364 return v8::Handle<v8::FunctionTemplate>(); | 376 return v8::Handle<v8::FunctionTemplate>(); |
| 365 } | 377 } |
| 366 | 378 |
| 367 static void SetNeedsDisplayOnAllLayers( | 379 static void SetNeedsDisplayOnAllLayers( |
| 368 const v8::FunctionCallbackInfo<v8::Value>& args) { | 380 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 369 GpuBenchmarkingContext context; | 381 GpuBenchmarkingContext context; |
| 370 if (!context.Init(true)) | 382 if (!context.Init(true)) |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 v8::Object::New(isolate), | 847 v8::Object::New(isolate), |
| 836 1, | 848 1, |
| 837 argv); | 849 argv); |
| 838 } | 850 } |
| 839 } | 851 } |
| 840 | 852 |
| 841 static void RunMicroBenchmark( | 853 static void RunMicroBenchmark( |
| 842 const v8::FunctionCallbackInfo<v8::Value>& args) { | 854 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 843 GpuBenchmarkingContext context; | 855 GpuBenchmarkingContext context; |
| 844 if (!context.Init(true)) { | 856 if (!context.Init(true)) { |
| 845 args.GetReturnValue().Set(false); | 857 args.GetReturnValue().Set(0); |
| 846 return; | 858 return; |
| 847 } | 859 } |
| 848 | 860 |
| 849 if (args.Length() != 3 || | 861 if (args.Length() != 3 || |
| 850 !args[0]->IsString() || | 862 !args[0]->IsString() || |
| 851 !args[1]->IsFunction() || | 863 !args[1]->IsFunction() || |
| 852 !args[2]->IsObject()) { | 864 !args[2]->IsObject()) { |
| 853 args.GetReturnValue().Set(false); | 865 args.GetReturnValue().Set(0); |
| 854 return; | 866 return; |
| 855 } | 867 } |
| 856 | 868 |
| 857 v8::Local<v8::Function> callback_local = | 869 v8::Local<v8::Function> callback_local = |
| 858 v8::Local<v8::Function>::Cast(args[1]); | 870 v8::Local<v8::Function>::Cast(args[1]); |
| 859 | 871 |
| 860 scoped_refptr<CallbackAndContext> callback_and_context = | 872 scoped_refptr<CallbackAndContext> callback_and_context = |
| 861 new CallbackAndContext(args.GetIsolate(), | 873 new CallbackAndContext(args.GetIsolate(), |
| 862 callback_local, | 874 callback_local, |
| 863 context.web_frame()->mainWorldScriptContext()); | 875 context.web_frame()->mainWorldScriptContext()); |
| 864 | 876 |
| 865 scoped_ptr<V8ValueConverter> converter = | 877 scoped_ptr<V8ValueConverter> converter = |
| 866 make_scoped_ptr(V8ValueConverter::create()); | 878 make_scoped_ptr(V8ValueConverter::create()); |
| 867 v8::Handle<v8::Context> v8_context = callback_and_context->GetContext(); | 879 v8::Handle<v8::Context> v8_context = callback_and_context->GetContext(); |
| 868 scoped_ptr<base::Value> value = | 880 scoped_ptr<base::Value> value = |
| 869 make_scoped_ptr(converter->FromV8Value(args[2], v8_context)); | 881 make_scoped_ptr(converter->FromV8Value(args[2], v8_context)); |
| 870 | 882 |
| 871 v8::String::Utf8Value benchmark(args[0]); | 883 v8::String::Utf8Value benchmark(args[0]); |
| 872 DCHECK(*benchmark); | 884 DCHECK(*benchmark); |
| 873 args.GetReturnValue().Set(context.compositor()->ScheduleMicroBenchmark( | 885 args.GetReturnValue().Set(context.compositor()->ScheduleMicroBenchmark( |
| 874 std::string(*benchmark), | 886 std::string(*benchmark), |
| 875 value.Pass(), | 887 value.Pass(), |
| 876 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context))); | 888 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context))); |
| 877 } | 889 } |
| 878 | 890 |
| 891 static void SendMessageToMicroBenchmark( |
| 892 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 893 GpuBenchmarkingContext context; |
| 894 if (!context.Init(true)) { |
| 895 args.GetReturnValue().Set(0); |
| 896 return; |
| 897 } |
| 898 |
| 899 if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsObject()) { |
| 900 args.GetReturnValue().Set(0); |
| 901 return; |
| 902 } |
| 903 |
| 904 scoped_ptr<V8ValueConverter> converter = |
| 905 make_scoped_ptr(V8ValueConverter::create()); |
| 906 v8::Handle<v8::Context> v8_context = |
| 907 context.web_frame()->mainWorldScriptContext(); |
| 908 scoped_ptr<base::Value> value = |
| 909 make_scoped_ptr(converter->FromV8Value(args[1], v8_context)); |
| 910 |
| 911 int id = 0; |
| 912 converter->FromV8Value(args[0], v8_context)->GetAsInteger(&id); |
| 913 args.GetReturnValue().Set( |
| 914 context.compositor()->SendMessageToMicroBenchmark(id, value.Pass())); |
| 915 } |
| 916 |
| 879 static void HasGpuProcess(const v8::FunctionCallbackInfo<v8::Value>& args) { | 917 static void HasGpuProcess(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 880 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel(); | 918 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel(); |
| 881 args.GetReturnValue().Set(!!gpu_channel); | 919 args.GetReturnValue().Set(!!gpu_channel); |
| 882 } | 920 } |
| 883 }; | 921 }; |
| 884 | 922 |
| 885 v8::Extension* GpuBenchmarkingExtension::Get() { | 923 v8::Extension* GpuBenchmarkingExtension::Get() { |
| 886 return new GpuBenchmarkingWrapper(); | 924 return new GpuBenchmarkingWrapper(); |
| 887 } | 925 } |
| 888 | 926 |
| 889 } // namespace content | 927 } // namespace content |
| OLD | NEW |