| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/accelerated_widget_mac/accelerated_widget_mac.h" | 5 #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 - (void)setContentsChanged; | 22 - (void)setContentsChanged; |
| 23 @end | 23 @end |
| 24 | 24 |
| 25 namespace ui { | 25 namespace ui { |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 typedef std::map<gfx::AcceleratedWidget,AcceleratedWidgetMac*> | 28 typedef std::map<gfx::AcceleratedWidget,AcceleratedWidgetMac*> |
| 29 WidgetToHelperMap; | 29 WidgetToHelperMap; |
| 30 base::LazyInstance<WidgetToHelperMap> g_widget_to_helper_map; | 30 base::LazyInstance<WidgetToHelperMap> g_widget_to_helper_map; |
| 31 | 31 |
| 32 AcceleratedWidgetMac* GetHelperFromAcceleratedWidget( | |
| 33 gfx::AcceleratedWidget widget) { | |
| 34 WidgetToHelperMap::const_iterator found = | |
| 35 g_widget_to_helper_map.Pointer()->find(widget); | |
| 36 // This can end up being accessed after the underlying widget has been | |
| 37 // destroyed, but while the ui::Compositor is still being destroyed. | |
| 38 // Return NULL in these cases. | |
| 39 if (found == g_widget_to_helper_map.Pointer()->end()) | |
| 40 return NULL; | |
| 41 return found->second; | |
| 42 } | |
| 43 | 32 |
| 44 } // namespace | 33 } // namespace |
| 45 | 34 |
| 46 //////////////////////////////////////////////////////////////////////////////// | 35 //////////////////////////////////////////////////////////////////////////////// |
| 47 // AcceleratedWidgetMac | 36 // AcceleratedWidgetMac |
| 48 | 37 |
| 49 AcceleratedWidgetMac::AcceleratedWidgetMac() : view_(nullptr) { | 38 AcceleratedWidgetMac::AcceleratedWidgetMac() : view_(nullptr) { |
| 50 // Disable the fade-in animation as the layers are added. | 39 // Disable the fade-in animation as the layers are added. |
| 51 ScopedCAActionDisabler disabler; | 40 ScopedCAActionDisabler disabler; |
| 52 | 41 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 | 83 |
| 95 if (fslp_coordinator_) { | 84 if (fslp_coordinator_) { |
| 96 fslp_coordinator_->WillLoseAcceleratedWidget(); | 85 fslp_coordinator_->WillLoseAcceleratedWidget(); |
| 97 DCHECK(!fslp_coordinator_); | 86 DCHECK(!fslp_coordinator_); |
| 98 } | 87 } |
| 99 | 88 |
| 100 // Disable the fade-out animation as the view is removed. | 89 // Disable the fade-out animation as the view is removed. |
| 101 ScopedCAActionDisabler disabler; | 90 ScopedCAActionDisabler disabler; |
| 102 | 91 |
| 103 [flipped_layer_ removeFromSuperlayer]; | 92 [flipped_layer_ removeFromSuperlayer]; |
| 104 DestroyCAContextLayer(ca_context_layer_); | 93 [content_layer_ removeFromSuperlayer]; |
| 105 DestroyLocalLayer(); | 94 [io_surface_layer_ removeFromSuperlayer]; |
| 95 content_layer_.reset(); |
| 96 io_surface_layer_.reset(); |
| 106 | 97 |
| 107 last_swap_size_dip_ = gfx::Size(); | 98 last_swap_size_dip_ = gfx::Size(); |
| 108 view_ = NULL; | 99 view_ = NULL; |
| 109 } | 100 } |
| 110 | 101 |
| 111 void AcceleratedWidgetMac::SetFullscreenLowPowerCoordinator( | 102 void AcceleratedWidgetMac::SetFullscreenLowPowerCoordinator( |
| 112 FullscreenLowPowerCoordinator* coordinator) { | 103 FullscreenLowPowerCoordinator* coordinator) { |
| 113 DCHECK(coordinator); | 104 DCHECK(coordinator); |
| 114 DCHECK(!fslp_coordinator_); | 105 DCHECK(!fslp_coordinator_); |
| 115 fslp_coordinator_ = coordinator; | 106 fslp_coordinator_ = coordinator; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 136 void AcceleratedWidgetMac::GetVSyncParameters( | 127 void AcceleratedWidgetMac::GetVSyncParameters( |
| 137 base::TimeTicks* timebase, base::TimeDelta* interval) const { | 128 base::TimeTicks* timebase, base::TimeDelta* interval) const { |
| 138 if (view_) { | 129 if (view_) { |
| 139 view_->AcceleratedWidgetGetVSyncParameters(timebase, interval); | 130 view_->AcceleratedWidgetGetVSyncParameters(timebase, interval); |
| 140 } else { | 131 } else { |
| 141 *timebase = base::TimeTicks(); | 132 *timebase = base::TimeTicks(); |
| 142 *interval = base::TimeDelta(); | 133 *interval = base::TimeDelta(); |
| 143 } | 134 } |
| 144 } | 135 } |
| 145 | 136 |
| 146 void AcceleratedWidgetMac::GotFrame( | 137 AcceleratedWidgetMac* AcceleratedWidgetMac::Get(gfx::AcceleratedWidget widget) { |
| 147 CAContextID ca_context_id, | 138 WidgetToHelperMap::const_iterator found = |
| 148 bool fullscreen_low_power_ca_context_valid, | 139 g_widget_to_helper_map.Pointer()->find(widget); |
| 149 CAContextID fullscreen_low_power_ca_context_id, | 140 // This can end up being accessed after the underlying widget has been |
| 150 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | 141 // destroyed, but while the ui::Compositor is still being destroyed. |
| 142 // Return NULL in these cases. |
| 143 if (found == g_widget_to_helper_map.Pointer()->end()) |
| 144 return nullptr; |
| 145 return found->second; |
| 146 } |
| 147 |
| 148 void AcceleratedWidgetMac::GotCALayerFrame( |
| 149 base::scoped_nsobject<CALayer> content_layer, |
| 150 bool fullscreen_low_power_layer_valid, |
| 151 base::scoped_nsobject<CALayer> fullscreen_low_power_layer, |
| 151 const gfx::Size& pixel_size, | 152 const gfx::Size& pixel_size, |
| 152 float scale_factor) { | 153 float scale_factor) { |
| 153 TRACE_EVENT0("ui", "AcceleratedWidgetMac::GotFrame"); | 154 TRACE_EVENT0("ui", "AcceleratedWidgetMac::GotCAContextFrame"); |
| 154 | |
| 155 // If there is no view and therefore no superview to draw into, early-out. | |
| 156 if (!view_) { | 155 if (!view_) { |
| 157 TRACE_EVENT0("ui", "No associated NSView"); | 156 TRACE_EVENT0("ui", "No associated NSView"); |
| 158 return; | 157 return; |
| 159 } | 158 } |
| 160 | |
| 161 // Disable the fade-in or fade-out effect if we create or remove layers. | |
| 162 ScopedCAActionDisabler disabler; | 159 ScopedCAActionDisabler disabler; |
| 163 | |
| 164 last_swap_size_dip_ = gfx::ConvertSizeToDIP(scale_factor, pixel_size); | 160 last_swap_size_dip_ = gfx::ConvertSizeToDIP(scale_factor, pixel_size); |
| 165 | 161 |
| 166 if (ca_context_id) { | 162 // Ensure that the content is in the CALayer hierarchy, and update fullscreen |
| 167 GotCAContextFrame(ca_context_id, fullscreen_low_power_ca_context_valid, | 163 // low power state. |
| 168 fullscreen_low_power_ca_context_id, pixel_size, | 164 if (content_layer_ != content_layer) { |
| 169 scale_factor); | 165 [flipped_layer_ addSublayer:content_layer]; |
| 170 } else { | 166 [content_layer_ removeFromSuperlayer]; |
| 171 GotIOSurfaceFrame(io_surface, pixel_size, scale_factor); | 167 content_layer_ = content_layer; |
| 172 } | 168 } |
| 173 | 169 if (fullscreen_low_power_layer_ != fullscreen_low_power_layer) { |
| 174 view_->AcceleratedWidgetSwapCompleted(); | |
| 175 } | |
| 176 | |
| 177 void AcceleratedWidgetMac::GotCAContextFrame( | |
| 178 CAContextID ca_context_id, | |
| 179 bool fullscreen_low_power_ca_context_valid, | |
| 180 CAContextID fullscreen_low_power_ca_context_id, | |
| 181 const gfx::Size& pixel_size, | |
| 182 float scale_factor) { | |
| 183 TRACE_EVENT0("ui", "AcceleratedWidgetMac::GotCAContextFrame"); | |
| 184 | |
| 185 // In the layer is replaced, keep the old one around until after the new one | |
| 186 // is installed to avoid flashes. | |
| 187 base::scoped_nsobject<CALayerHost> old_ca_context_layer = | |
| 188 ca_context_layer_; | |
| 189 | |
| 190 // Create the layer to host the layer exported by the GPU process with this | |
| 191 // particular CAContext ID. | |
| 192 if ([ca_context_layer_ contextId] != ca_context_id) { | |
| 193 TRACE_EVENT0("ui", "Creating a new CALayerHost"); | |
| 194 ca_context_layer_.reset([[CALayerHost alloc] init]); | |
| 195 [ca_context_layer_ setContextId:ca_context_id]; | |
| 196 [ca_context_layer_ | |
| 197 setAutoresizingMask:kCALayerMaxXMargin|kCALayerMaxYMargin]; | |
| 198 [flipped_layer_ addSublayer:ca_context_layer_]; | |
| 199 } | |
| 200 if ([fullscreen_low_power_layer_ contextId] != | |
| 201 fullscreen_low_power_ca_context_id) { | |
| 202 TRACE_EVENT0("ui", "Creating a new CALayerHost"); | |
| 203 if (fslp_coordinator_) { | 170 if (fslp_coordinator_) { |
| 204 fslp_coordinator_->WillLoseAcceleratedWidget(); | 171 fslp_coordinator_->WillLoseAcceleratedWidget(); |
| 205 DCHECK(!fslp_coordinator_); | 172 DCHECK(!fslp_coordinator_); |
| 206 } | 173 } |
| 207 fullscreen_low_power_layer_.reset([[CALayerHost alloc] init]); | 174 fullscreen_low_power_layer_ = fullscreen_low_power_layer; |
| 208 [fullscreen_low_power_layer_ | |
| 209 setContextId:fullscreen_low_power_ca_context_id]; | |
| 210 } | 175 } |
| 176 if (fslp_coordinator_) |
| 177 fslp_coordinator_->SetLowPowerLayerValid(fullscreen_low_power_layer_valid); |
| 211 | 178 |
| 212 if (fslp_coordinator_) { | 179 // Ensure the IOSurface is removed. |
| 213 fslp_coordinator_->SetLowPowerLayerValid( | 180 if (io_surface_layer_) { |
| 214 fullscreen_low_power_ca_context_valid); | 181 [io_surface_layer_ removeFromSuperlayer]; |
| 182 io_surface_layer_.reset(); |
| 215 } | 183 } |
| 216 | 184 view_->AcceleratedWidgetSwapCompleted(); |
| 217 // If this replacing a same-type layer, remove it now that the new layer is | |
| 218 // in the hierarchy. | |
| 219 if (old_ca_context_layer != ca_context_layer_) | |
| 220 DestroyCAContextLayer(old_ca_context_layer); | |
| 221 | |
| 222 // Remove any different-type layers that this is replacing. | |
| 223 DestroyLocalLayer(); | |
| 224 } | |
| 225 | |
| 226 void AcceleratedWidgetMac::EnsureLocalLayer() { | |
| 227 if (!local_layer_) { | |
| 228 local_layer_.reset([[CALayer alloc] init]); | |
| 229 // Setting contents gravity is necessary to prevent the layer from being | |
| 230 // scaled during dyanmic resizes (especially with devtools open). | |
| 231 [local_layer_ setContentsGravity:kCAGravityTopLeft]; | |
| 232 [local_layer_ setAnchorPoint:CGPointMake(0, 0)]; | |
| 233 [flipped_layer_ addSublayer:local_layer_]; | |
| 234 } | |
| 235 } | 185 } |
| 236 | 186 |
| 237 void AcceleratedWidgetMac::GotIOSurfaceFrame( | 187 void AcceleratedWidgetMac::GotIOSurfaceFrame( |
| 238 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | 188 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, |
| 239 const gfx::Size& pixel_size, | 189 const gfx::Size& pixel_size, |
| 240 float scale_factor) { | 190 float scale_factor) { |
| 241 TRACE_EVENT0("ui", "AcceleratedWidgetMac::GotIOSurfaceFrame"); | 191 TRACE_EVENT0("ui", "AcceleratedWidgetMac::GotIOSurfaceFrame"); |
| 192 if (!view_) { |
| 193 TRACE_EVENT0("ui", "No associated NSView"); |
| 194 return; |
| 195 } |
| 196 ScopedCAActionDisabler disabler; |
| 197 last_swap_size_dip_ = gfx::ConvertSizeToDIP(scale_factor, pixel_size); |
| 242 | 198 |
| 243 // If there is not a layer for local frames, create one. | 199 // Create (if needed) and update the IOSurface layer with new content. |
| 244 EnsureLocalLayer(); | 200 if (!io_surface_layer_) { |
| 201 io_surface_layer_.reset([[CALayer alloc] init]); |
| 202 [io_surface_layer_ setContentsGravity:kCAGravityTopLeft]; |
| 203 [io_surface_layer_ setAnchorPoint:CGPointMake(0, 0)]; |
| 204 [flipped_layer_ addSublayer:io_surface_layer_]; |
| 205 } |
| 206 id new_contents = static_cast<id>(io_surface.get()); |
| 207 if (new_contents && new_contents == [io_surface_layer_ contents]) |
| 208 [io_surface_layer_ setContentsChanged]; |
| 209 else |
| 210 [io_surface_layer_ setContents:new_contents]; |
| 211 [io_surface_layer_ setBounds:CGRectMake(0, 0, last_swap_size_dip_.width(), |
| 212 last_swap_size_dip_.height())]; |
| 213 if ([io_surface_layer_ contentsScale] != scale_factor) |
| 214 [io_surface_layer_ setContentsScale:scale_factor]; |
| 245 | 215 |
| 246 id new_contents = static_cast<id>(io_surface.get()); | 216 // Ensure that the content layer is removed. |
| 247 | 217 if (content_layer_) { |
| 248 if (new_contents && new_contents == [local_layer_ contents]) { | 218 [content_layer_ removeFromSuperlayer]; |
| 249 [local_layer_ setContentsChanged]; | 219 content_layer_.reset(); |
| 250 } else { | |
| 251 [local_layer_ setContents:new_contents]; | |
| 252 } | 220 } |
| 253 | 221 view_->AcceleratedWidgetSwapCompleted(); |
| 254 [local_layer_ setBounds:CGRectMake(0, 0, pixel_size.width() / scale_factor, | |
| 255 pixel_size.height() / scale_factor)]; | |
| 256 | |
| 257 if ([local_layer_ contentsScale] != scale_factor) | |
| 258 [local_layer_ setContentsScale:scale_factor]; | |
| 259 | |
| 260 // Remove any different-type layers that this is replacing. | |
| 261 DestroyCAContextLayer(ca_context_layer_); | |
| 262 } | |
| 263 | |
| 264 void AcceleratedWidgetMac::DestroyCAContextLayer( | |
| 265 base::scoped_nsobject<CALayerHost> ca_context_layer) { | |
| 266 if (!ca_context_layer) | |
| 267 return; | |
| 268 [ca_context_layer removeFromSuperlayer]; | |
| 269 if (ca_context_layer == ca_context_layer_) | |
| 270 ca_context_layer_.reset(); | |
| 271 } | |
| 272 | |
| 273 void AcceleratedWidgetMac::DestroyLocalLayer() { | |
| 274 if (!local_layer_) | |
| 275 return; | |
| 276 [local_layer_ removeFromSuperlayer]; | |
| 277 local_layer_.reset(); | |
| 278 } | |
| 279 | |
| 280 void AcceleratedWidgetMacGotFrame( | |
| 281 gfx::AcceleratedWidget widget, | |
| 282 CAContextID ca_context_id, | |
| 283 bool fullscreen_low_power_ca_context_valid, | |
| 284 CAContextID fullscreen_low_power_ca_context_id, | |
| 285 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | |
| 286 const gfx::Size& pixel_size, | |
| 287 float scale_factor, | |
| 288 base::TimeTicks* vsync_timebase, | |
| 289 base::TimeDelta* vsync_interval) { | |
| 290 if (vsync_timebase) | |
| 291 *vsync_timebase = base::TimeTicks(); | |
| 292 if (vsync_interval) | |
| 293 *vsync_interval = base::TimeDelta(); | |
| 294 | |
| 295 AcceleratedWidgetMac* accelerated_widget_mac = | |
| 296 GetHelperFromAcceleratedWidget(widget); | |
| 297 | |
| 298 if (accelerated_widget_mac) { | |
| 299 accelerated_widget_mac->GotFrame(ca_context_id, | |
| 300 fullscreen_low_power_ca_context_valid, | |
| 301 fullscreen_low_power_ca_context_id, | |
| 302 io_surface, pixel_size, scale_factor); | |
| 303 if (vsync_timebase && vsync_interval) { | |
| 304 accelerated_widget_mac->GetVSyncParameters(vsync_timebase, | |
| 305 vsync_interval); | |
| 306 } | |
| 307 } | |
| 308 } | 222 } |
| 309 | 223 |
| 310 } // namespace ui | 224 } // namespace ui |
| OLD | NEW |