| 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/browser/renderer_host/render_widget_host_view_android.h" | 5 #include "content/browser/renderer_host/render_widget_host_view_android.h" | 
| 6 | 6 | 
| 7 #include <android/bitmap.h> | 7 #include <android/bitmap.h> | 
| 8 | 8 | 
| 9 #include "base/android/build_info.h" | 9 #include "base/android/build_info.h" | 
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" | 
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 210 bool HasMobileViewport(const cc::CompositorFrameMetadata& frame_metadata) { | 210 bool HasMobileViewport(const cc::CompositorFrameMetadata& frame_metadata) { | 
| 211   float window_width_dip = | 211   float window_width_dip = | 
| 212       frame_metadata.page_scale_factor * | 212       frame_metadata.page_scale_factor * | 
| 213           frame_metadata.scrollable_viewport_size.width(); | 213           frame_metadata.scrollable_viewport_size.width(); | 
| 214   float content_width_css = frame_metadata.root_layer_size.width(); | 214   float content_width_css = frame_metadata.root_layer_size.width(); | 
| 215   return content_width_css <= window_width_dip + kMobileViewportWidthEpsilon; | 215   return content_width_css <= window_width_dip + kMobileViewportWidthEpsilon; | 
| 216 } | 216 } | 
| 217 | 217 | 
| 218 }  // anonymous namespace | 218 }  // anonymous namespace | 
| 219 | 219 | 
|  | 220 ReadbackRequest::ReadbackRequest( | 
|  | 221     float scale, | 
|  | 222     SkColorType color_type, | 
|  | 223     gfx::Rect src_subrect, | 
|  | 224     const base::Callback<void(bool, const SkBitmap&)>& result_callback) | 
|  | 225     : scale_(scale), | 
|  | 226       color_type_(color_type), | 
|  | 227       src_subrect_(src_subrect), | 
|  | 228       result_callback_(result_callback) { | 
|  | 229 } | 
|  | 230 | 
|  | 231 ReadbackRequest::ReadbackRequest() { | 
|  | 232 } | 
|  | 233 | 
|  | 234 ReadbackRequest::~ReadbackRequest() { | 
|  | 235 } | 
|  | 236 | 
| 220 RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo( | 237 RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo( | 
| 221     uint32 output_id, | 238     uint32 output_id, | 
| 222     scoped_ptr<cc::CompositorFrame> output_frame) | 239     scoped_ptr<cc::CompositorFrame> output_frame) | 
| 223     : output_surface_id(output_id), frame(output_frame.Pass()) {} | 240     : output_surface_id(output_id), frame(output_frame.Pass()) {} | 
| 224 | 241 | 
| 225 RenderWidgetHostViewAndroid::LastFrameInfo::~LastFrameInfo() {} | 242 RenderWidgetHostViewAndroid::LastFrameInfo::~LastFrameInfo() {} | 
| 226 | 243 | 
| 227 RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid( | 244 RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid( | 
| 228     RenderWidgetHostImpl* widget_host, | 245     RenderWidgetHostImpl* widget_host, | 
| 229     ContentViewCoreImpl* content_view_core) | 246     ContentViewCoreImpl* content_view_core) | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 252       observing_root_window_(false) { | 269       observing_root_window_(false) { | 
| 253   host_->SetView(this); | 270   host_->SetView(this); | 
| 254   SetContentViewCore(content_view_core); | 271   SetContentViewCore(content_view_core); | 
| 255   ImageTransportFactoryAndroid::AddObserver(this); | 272   ImageTransportFactoryAndroid::AddObserver(this); | 
| 256 } | 273 } | 
| 257 | 274 | 
| 258 RenderWidgetHostViewAndroid::~RenderWidgetHostViewAndroid() { | 275 RenderWidgetHostViewAndroid::~RenderWidgetHostViewAndroid() { | 
| 259   ImageTransportFactoryAndroid::RemoveObserver(this); | 276   ImageTransportFactoryAndroid::RemoveObserver(this); | 
| 260   SetContentViewCore(NULL); | 277   SetContentViewCore(NULL); | 
| 261   DCHECK(ack_callbacks_.empty()); | 278   DCHECK(ack_callbacks_.empty()); | 
|  | 279   DCHECK(readbacks_waiting_for_frame_.empty()); | 
| 262   if (resource_collection_.get()) | 280   if (resource_collection_.get()) | 
| 263     resource_collection_->SetClient(NULL); | 281     resource_collection_->SetClient(NULL); | 
| 264 } | 282 } | 
| 265 | 283 | 
| 266 | 284 | 
| 267 bool RenderWidgetHostViewAndroid::OnMessageReceived( | 285 bool RenderWidgetHostViewAndroid::OnMessageReceived( | 
| 268     const IPC::Message& message) { | 286     const IPC::Message& message) { | 
| 269   bool handled = true; | 287   bool handled = true; | 
| 270   IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewAndroid, message) | 288   IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewAndroid, message) | 
| 271     IPC_MESSAGE_HANDLER(ViewHostMsg_StartContentIntent, OnStartContentIntent) | 289     IPC_MESSAGE_HANDLER(ViewHostMsg_StartContentIntent, OnStartContentIntent) | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 335 void RenderWidgetHostViewAndroid::SetSize(const gfx::Size& size) { | 353 void RenderWidgetHostViewAndroid::SetSize(const gfx::Size& size) { | 
| 336   // Ignore the given size as only the Java code has the power to | 354   // Ignore the given size as only the Java code has the power to | 
| 337   // resize the view on Android. | 355   // resize the view on Android. | 
| 338   default_size_ = size; | 356   default_size_ = size; | 
| 339 } | 357 } | 
| 340 | 358 | 
| 341 void RenderWidgetHostViewAndroid::SetBounds(const gfx::Rect& rect) { | 359 void RenderWidgetHostViewAndroid::SetBounds(const gfx::Rect& rect) { | 
| 342   SetSize(rect.size()); | 360   SetSize(rect.size()); | 
| 343 } | 361 } | 
| 344 | 362 | 
|  | 363 void RenderWidgetHostViewAndroid::AbortPendingReadbackRequests() { | 
|  | 364   while (!readbacks_waiting_for_frame_.empty()) { | 
|  | 365     ReadbackRequest& readback_request = readbacks_waiting_for_frame_.front(); | 
|  | 366     readback_request.GetResultCallback().Run(false, SkBitmap()); | 
|  | 367     readbacks_waiting_for_frame_.pop(); | 
|  | 368   } | 
|  | 369 } | 
|  | 370 | 
| 345 void RenderWidgetHostViewAndroid::GetScaledContentBitmap( | 371 void RenderWidgetHostViewAndroid::GetScaledContentBitmap( | 
| 346     float scale, | 372     float scale, | 
| 347     SkColorType color_type, | 373     SkColorType color_type, | 
| 348     gfx::Rect src_subrect, | 374     gfx::Rect src_subrect, | 
| 349     const base::Callback<void(bool, const SkBitmap&)>& result_callback) { | 375     const base::Callback<void(bool, const SkBitmap&)>& result_callback) { | 
| 350   if (!host_ || host_->is_hidden()) { | 376   if (!host_ || host_->is_hidden()) { | 
| 351     result_callback.Run(false, SkBitmap()); | 377     result_callback.Run(false, SkBitmap()); | 
| 352     return; | 378     return; | 
| 353   } | 379   } | 
| 354   if (!IsSurfaceAvailableForCopy()) { | 380   if (!IsSurfaceAvailableForCopy()) { | 
| 355     // TODO(Sikugu): allow a read-back request to wait for a first frame if it | 381     // The view is visible, probably the frame has not yet arrived. | 
| 356     // was invoked while no frame was received yet | 382     // Just add the ReadbackRequest to queue and wait for frame arrival | 
| 357     result_callback.Run(false, SkBitmap()); | 383     // to get this request processed. | 
|  | 384     readbacks_waiting_for_frame_.push( | 
|  | 385         ReadbackRequest(scale, color_type, src_subrect, result_callback)); | 
| 358     return; | 386     return; | 
| 359   } | 387   } | 
| 360 | 388 | 
| 361   gfx::Size bounds = layer_->bounds(); | 389   gfx::Size bounds = layer_->bounds(); | 
| 362   if (src_subrect.IsEmpty()) | 390   if (src_subrect.IsEmpty()) | 
| 363     src_subrect = gfx::Rect(bounds); | 391     src_subrect = gfx::Rect(bounds); | 
| 364   DCHECK_LE(src_subrect.width() + src_subrect.x(), bounds.width()); | 392   DCHECK_LE(src_subrect.width() + src_subrect.x(), bounds.width()); | 
| 365   DCHECK_LE(src_subrect.height() + src_subrect.y(), bounds.height()); | 393   DCHECK_LE(src_subrect.height() + src_subrect.y(), bounds.height()); | 
| 366   const gfx::Display& display = | 394   const gfx::Display& display = | 
| 367       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); | 395       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); | 
| 368   float device_scale_factor = display.device_scale_factor(); | 396   float device_scale_factor = display.device_scale_factor(); | 
| 369   DCHECK_GT(device_scale_factor, 0); | 397   DCHECK_GT(device_scale_factor, 0); | 
| 370   gfx::Size dst_size( | 398   gfx::Size dst_size( | 
| 371       gfx::ToCeiledSize(gfx::ScaleSize(bounds, scale / device_scale_factor))); | 399       gfx::ToCeiledSize(gfx::ScaleSize(bounds, scale / device_scale_factor))); | 
| 372   CopyFromCompositingSurface( | 400   CopyFromCompositingSurface( | 
| 373       src_subrect, dst_size, result_callback, color_type); | 401       src_subrect, dst_size, result_callback, color_type); | 
| 374 } | 402 } | 
| 375 | 403 | 
| 376 bool RenderWidgetHostViewAndroid::HasValidFrame() const { | 404 bool RenderWidgetHostViewAndroid::HasValidFrame() const { | 
| 377   if (!content_view_core_) | 405   if (!content_view_core_) | 
| 378     return false; | 406     return false; | 
| 379   if (!layer_) | 407   if (!layer_) | 
| 380     return false; | 408     return false; | 
| 381 | 409 | 
| 382   if (texture_size_in_layer_.IsEmpty()) | 410   if (texture_size_in_layer_.IsEmpty()) | 
| 383     return false; | 411     return false; | 
| 384 | 412   // This tell us whether a valid frame has arrived or not. | 
| 385   if (!frame_evictor_->HasFrame()) | 413   if (!frame_evictor_->HasFrame()) | 
| 386     return false; | 414     return false; | 
| 387 | 415 | 
| 388   return true; | 416   return true; | 
| 389 } | 417 } | 
| 390 | 418 | 
| 391 gfx::NativeView RenderWidgetHostViewAndroid::GetNativeView() const { | 419 gfx::NativeView RenderWidgetHostViewAndroid::GetNativeView() const { | 
| 392   return content_view_core_->GetViewAndroid(); | 420   return content_view_core_->GetViewAndroid(); | 
| 393 } | 421 } | 
| 394 | 422 | 
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 450 | 478 | 
| 451 void RenderWidgetHostViewAndroid::Hide() { | 479 void RenderWidgetHostViewAndroid::Hide() { | 
| 452   if (!is_showing_) | 480   if (!is_showing_) | 
| 453     return; | 481     return; | 
| 454 | 482 | 
| 455   is_showing_ = false; | 483   is_showing_ = false; | 
| 456   if (layer_ && locks_on_frame_count_ == 0) | 484   if (layer_ && locks_on_frame_count_ == 0) | 
| 457     layer_->SetHideLayerAndSubtree(true); | 485     layer_->SetHideLayerAndSubtree(true); | 
| 458 | 486 | 
| 459   frame_evictor_->SetVisible(false); | 487   frame_evictor_->SetVisible(false); | 
|  | 488   // We don't know if we will ever get a frame if we are hiding the renderer, so | 
|  | 489   // we need to cancel all requests | 
|  | 490   AbortPendingReadbackRequests(); | 
| 460   WasHidden(); | 491   WasHidden(); | 
| 461 } | 492 } | 
| 462 | 493 | 
| 463 bool RenderWidgetHostViewAndroid::IsShowing() { | 494 bool RenderWidgetHostViewAndroid::IsShowing() { | 
| 464   // ContentViewCoreImpl represents the native side of the Java | 495   // ContentViewCoreImpl represents the native side of the Java | 
| 465   // ContentViewCore.  It being NULL means that it is not attached | 496   // ContentViewCore.  It being NULL means that it is not attached | 
| 466   // to the View system yet, so we treat this RWHVA as hidden. | 497   // to the View system yet, so we treat this RWHVA as hidden. | 
| 467   return is_showing_ && content_view_core_; | 498   return is_showing_ && content_view_core_; | 
| 468 } | 499 } | 
| 469 | 500 | 
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 891 void RenderWidgetHostViewAndroid::UnusedResourcesAreAvailable() { | 922 void RenderWidgetHostViewAndroid::UnusedResourcesAreAvailable() { | 
| 892   if (ack_callbacks_.size()) | 923   if (ack_callbacks_.size()) | 
| 893     return; | 924     return; | 
| 894   SendReturnedDelegatedResources(last_output_surface_id_); | 925   SendReturnedDelegatedResources(last_output_surface_id_); | 
| 895 } | 926 } | 
| 896 | 927 | 
| 897 void RenderWidgetHostViewAndroid::DestroyDelegatedContent() { | 928 void RenderWidgetHostViewAndroid::DestroyDelegatedContent() { | 
| 898   RemoveLayers(); | 929   RemoveLayers(); | 
| 899   frame_provider_ = NULL; | 930   frame_provider_ = NULL; | 
| 900   layer_ = NULL; | 931   layer_ = NULL; | 
|  | 932   // This gets called when ever any eviction, loosing resources, swapping | 
|  | 933   // problems are encountered and so we abort any pending readbacks here. | 
|  | 934   AbortPendingReadbackRequests(); | 
| 901 } | 935 } | 
| 902 | 936 | 
| 903 void RenderWidgetHostViewAndroid::SwapDelegatedFrame( | 937 void RenderWidgetHostViewAndroid::SwapDelegatedFrame( | 
| 904     uint32 output_surface_id, | 938     uint32 output_surface_id, | 
| 905     scoped_ptr<cc::DelegatedFrameData> frame_data) { | 939     scoped_ptr<cc::DelegatedFrameData> frame_data) { | 
| 906   bool has_content = !texture_size_in_layer_.IsEmpty(); | 940   bool has_content = !texture_size_in_layer_.IsEmpty(); | 
| 907 | 941 | 
| 908   if (output_surface_id != last_output_surface_id_) { | 942   if (output_surface_id != last_output_surface_id_) { | 
| 909     // Drop the cc::DelegatedFrameResourceCollection so that we will not return | 943     // Drop the cc::DelegatedFrameResourceCollection so that we will not return | 
| 910     // any resources from the old output surface with the new output surface id. | 944     // any resources from the old output surface with the new output surface id. | 
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1009       frame->delegated_frame_data->render_pass_list.back(); | 1043       frame->delegated_frame_data->render_pass_list.back(); | 
| 1010   texture_size_in_layer_ = root_pass->output_rect.size(); | 1044   texture_size_in_layer_ = root_pass->output_rect.size(); | 
| 1011   ComputeContentsSize(frame->metadata); | 1045   ComputeContentsSize(frame->metadata); | 
| 1012 | 1046 | 
| 1013   SwapDelegatedFrame(output_surface_id, frame->delegated_frame_data.Pass()); | 1047   SwapDelegatedFrame(output_surface_id, frame->delegated_frame_data.Pass()); | 
| 1014   frame_evictor_->SwappedFrame(!host_->is_hidden()); | 1048   frame_evictor_->SwappedFrame(!host_->is_hidden()); | 
| 1015 | 1049 | 
| 1016   // As the metadata update may trigger view invalidation, always call it after | 1050   // As the metadata update may trigger view invalidation, always call it after | 
| 1017   // any potential compositor scheduling. | 1051   // any potential compositor scheduling. | 
| 1018   OnFrameMetadataUpdated(frame->metadata); | 1052   OnFrameMetadataUpdated(frame->metadata); | 
|  | 1053   // Check if we have any pending readbacks, see if we have a frame available | 
|  | 1054   // and process them here. | 
|  | 1055   if (!readbacks_waiting_for_frame_.empty()) { | 
|  | 1056     while (!readbacks_waiting_for_frame_.empty()) { | 
|  | 1057       ReadbackRequest& readback_request = readbacks_waiting_for_frame_.front(); | 
|  | 1058       GetScaledContentBitmap(readback_request.GetScale(), | 
|  | 1059                              readback_request.GetColorFormat(), | 
|  | 1060                              readback_request.GetCaptureRect(), | 
|  | 1061                              readback_request.GetResultCallback()); | 
|  | 1062       readbacks_waiting_for_frame_.pop(); | 
|  | 1063     } | 
|  | 1064   } | 
| 1019 } | 1065 } | 
| 1020 | 1066 | 
| 1021 void RenderWidgetHostViewAndroid::OnSwapCompositorFrame( | 1067 void RenderWidgetHostViewAndroid::OnSwapCompositorFrame( | 
| 1022     uint32 output_surface_id, | 1068     uint32 output_surface_id, | 
| 1023     scoped_ptr<cc::CompositorFrame> frame) { | 1069     scoped_ptr<cc::CompositorFrame> frame) { | 
| 1024   InternalSwapCompositorFrame(output_surface_id, frame.Pass()); | 1070   InternalSwapCompositorFrame(output_surface_id, frame.Pass()); | 
| 1025 } | 1071 } | 
| 1026 | 1072 | 
| 1027 void RenderWidgetHostViewAndroid::RetainFrame( | 1073 void RenderWidgetHostViewAndroid::RetainFrame( | 
| 1028     uint32 output_surface_id, | 1074     uint32 output_surface_id, | 
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1236 } | 1282 } | 
| 1237 | 1283 | 
| 1238 void RenderWidgetHostViewAndroid::AcceleratedSurfaceRelease() { | 1284 void RenderWidgetHostViewAndroid::AcceleratedSurfaceRelease() { | 
| 1239   NOTREACHED(); | 1285   NOTREACHED(); | 
| 1240 } | 1286 } | 
| 1241 | 1287 | 
| 1242 void RenderWidgetHostViewAndroid::EvictDelegatedFrame() { | 1288 void RenderWidgetHostViewAndroid::EvictDelegatedFrame() { | 
| 1243   if (layer_.get()) | 1289   if (layer_.get()) | 
| 1244     DestroyDelegatedContent(); | 1290     DestroyDelegatedContent(); | 
| 1245   frame_evictor_->DiscardedFrame(); | 1291   frame_evictor_->DiscardedFrame(); | 
|  | 1292   // We are evicting the delegated frame, | 
|  | 1293   // so there should be no pending readback requests | 
|  | 1294   DCHECK(readbacks_waiting_for_frame_.empty()); | 
| 1246 } | 1295 } | 
| 1247 | 1296 | 
| 1248 bool RenderWidgetHostViewAndroid::HasAcceleratedSurface( | 1297 bool RenderWidgetHostViewAndroid::HasAcceleratedSurface( | 
| 1249     const gfx::Size& desired_size) { | 1298     const gfx::Size& desired_size) { | 
| 1250   NOTREACHED(); | 1299   NOTREACHED(); | 
| 1251   return false; | 1300   return false; | 
| 1252 } | 1301 } | 
| 1253 | 1302 | 
| 1254 void RenderWidgetHostViewAndroid::GetScreenInfo(blink::WebScreenInfo* result) { | 1303 void RenderWidgetHostViewAndroid::GetScreenInfo(blink::WebScreenInfo* result) { | 
| 1255   // ScreenInfo isn't tied to the widget on Android. Always return the default. | 1304   // ScreenInfo isn't tied to the widget on Android. Always return the default. | 
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1601 void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) { | 1650 void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) { | 
| 1602   if (Animate(begin_frame_time)) | 1651   if (Animate(begin_frame_time)) | 
| 1603     SetNeedsAnimate(); | 1652     SetNeedsAnimate(); | 
| 1604 } | 1653 } | 
| 1605 | 1654 | 
| 1606 void RenderWidgetHostViewAndroid::OnLostResources() { | 1655 void RenderWidgetHostViewAndroid::OnLostResources() { | 
| 1607   ReleaseLocksOnSurface(); | 1656   ReleaseLocksOnSurface(); | 
| 1608   if (layer_.get()) | 1657   if (layer_.get()) | 
| 1609     DestroyDelegatedContent(); | 1658     DestroyDelegatedContent(); | 
| 1610   DCHECK(ack_callbacks_.empty()); | 1659   DCHECK(ack_callbacks_.empty()); | 
|  | 1660   // We should not loose a frame if we have readback requests pending. | 
|  | 1661   DCHECK(readbacks_waiting_for_frame_.empty()); | 
| 1611 } | 1662 } | 
| 1612 | 1663 | 
| 1613 // static | 1664 // static | 
| 1614 void | 1665 void | 
| 1615 RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResultForDelegatedReadback( | 1666 RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResultForDelegatedReadback( | 
| 1616     const gfx::Size& dst_size_in_pixel, | 1667     const gfx::Size& dst_size_in_pixel, | 
| 1617     const SkColorType color_type, | 1668     const SkColorType color_type, | 
| 1618     const base::TimeTicks& start_time, | 1669     const base::TimeTicks& start_time, | 
| 1619     scoped_refptr<cc::Layer> readback_layer, | 1670     scoped_refptr<cc::Layer> readback_layer, | 
| 1620     const base::Callback<void(bool, const SkBitmap&)>& callback, | 1671     const base::Callback<void(bool, const SkBitmap&)>& callback, | 
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1742   results->orientationAngle = display.RotationAsDegree(); | 1793   results->orientationAngle = display.RotationAsDegree(); | 
| 1743   results->orientationType = | 1794   results->orientationType = | 
| 1744       RenderWidgetHostViewBase::GetOrientationTypeForMobile(display); | 1795       RenderWidgetHostViewBase::GetOrientationTypeForMobile(display); | 
| 1745   gfx::DeviceDisplayInfo info; | 1796   gfx::DeviceDisplayInfo info; | 
| 1746   results->depth = info.GetBitsPerPixel(); | 1797   results->depth = info.GetBitsPerPixel(); | 
| 1747   results->depthPerComponent = info.GetBitsPerComponent(); | 1798   results->depthPerComponent = info.GetBitsPerComponent(); | 
| 1748   results->isMonochrome = (results->depthPerComponent == 0); | 1799   results->isMonochrome = (results->depthPerComponent == 0); | 
| 1749 } | 1800 } | 
| 1750 | 1801 | 
| 1751 } // namespace content | 1802 } // namespace content | 
| OLD | NEW | 
|---|