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

Side by Side Diff: cc/occlusion_tracker.cc

Issue 12774006: cc: Chromify Layer and LayerImpl classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: MoreAndroidCompilings Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « cc/nine_patch_layer_unittest.cc ('k') | cc/occlusion_tracker_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 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 "cc/occlusion_tracker.h" 5 #include "cc/occlusion_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "cc/layer.h" 9 #include "cc/layer.h"
10 #include "cc/layer_impl.h" 10 #include "cc/layer_impl.h"
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 gfx::ToEnclosedRect(transformed_quad.BoundingBox()); 92 gfx::ToEnclosedRect(transformed_quad.BoundingBox());
93 DCHECK(!clipped); // We only map if the transform preserves axis alignment. 93 DCHECK(!clipped); // We only map if the transform preserves axis alignment.
94 if (have_clip_rect) 94 if (have_clip_rect)
95 transformed_rect.Intersect(clip_rect_in_new_target); 95 transformed_rect.Intersect(clip_rect_in_new_target);
96 transformed_region.Union(transformed_rect); 96 transformed_region.Union(transformed_rect);
97 } 97 }
98 return transformed_region; 98 return transformed_region;
99 } 99 }
100 100
101 static inline bool LayerOpacityKnown(const Layer* layer) { 101 static inline bool LayerOpacityKnown(const Layer* layer) {
102 return !layer->drawOpacityIsAnimating(); 102 return !layer->draw_opacity_is_animating();
103 } 103 }
104 static inline bool LayerOpacityKnown(const LayerImpl* layer) { 104 static inline bool LayerOpacityKnown(const LayerImpl* layer) {
105 return true; 105 return true;
106 } 106 }
107 static inline bool LayerTransformsToTargetKnown(const Layer* layer) { 107 static inline bool LayerTransformsToTargetKnown(const Layer* layer) {
108 return !layer->drawTransformIsAnimating(); 108 return !layer->draw_transform_is_animating();
109 } 109 }
110 static inline bool LayerTransformsToTargetKnown(const LayerImpl* layer) { 110 static inline bool LayerTransformsToTargetKnown(const LayerImpl* layer) {
111 return true; 111 return true;
112 } 112 }
113 113
114 static inline bool SurfaceOpacityKnown(const RenderSurface* rs) { 114 static inline bool SurfaceOpacityKnown(const RenderSurface* rs) {
115 return !rs->draw_opacity_is_animating(); 115 return !rs->draw_opacity_is_animating();
116 } 116 }
117 static inline bool SurfaceOpacityKnown(const RenderSurfaceImpl* rs) { 117 static inline bool SurfaceOpacityKnown(const RenderSurfaceImpl* rs) {
118 return true; 118 return true;
119 } 119 }
120 static inline bool SurfaceTransformsToTargetKnown(const RenderSurface* rs) { 120 static inline bool SurfaceTransformsToTargetKnown(const RenderSurface* rs) {
121 return !rs->target_surface_transforms_are_animating(); 121 return !rs->target_surface_transforms_are_animating();
122 } 122 }
123 static inline bool SurfaceTransformsToTargetKnown(const RenderSurfaceImpl* rs) { 123 static inline bool SurfaceTransformsToTargetKnown(const RenderSurfaceImpl* rs) {
124 return true; 124 return true;
125 } 125 }
126 static inline bool SurfaceTransformsToScreenKnown(const RenderSurface* rs) { 126 static inline bool SurfaceTransformsToScreenKnown(const RenderSurface* rs) {
127 return !rs->screen_space_transforms_are_animating(); 127 return !rs->screen_space_transforms_are_animating();
128 } 128 }
129 static inline bool SurfaceTransformsToScreenKnown(const RenderSurfaceImpl* rs) { 129 static inline bool SurfaceTransformsToScreenKnown(const RenderSurfaceImpl* rs) {
130 return true; 130 return true;
131 } 131 }
132 132
133 static inline bool LayerIsInUnsorted3dRenderingContext(const Layer* layer) { 133 static inline bool LayerIsInUnsorted3dRenderingContext(const Layer* layer) {
134 return layer->parent() && layer->parent()->preserves3D(); 134 return layer->parent() && layer->parent()->preserves_3d();
135 } 135 }
136 static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) { 136 static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) {
137 return false; 137 return false;
138 } 138 }
139 139
140 template <typename LayerType, typename RenderSurfaceType> 140 template <typename LayerType, typename RenderSurfaceType>
141 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget( 141 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget(
142 const LayerType* new_target) { 142 const LayerType* new_target) {
143 if (!stack_.empty() && stack_.back().target == new_target) 143 if (!stack_.empty() && stack_.back().target == new_target)
144 return; 144 return;
145 145
146 const LayerType* old_target = NULL; 146 const LayerType* old_target = NULL;
147 const RenderSurfaceType* old_ancestor_that_moves_pixels = NULL; 147 const RenderSurfaceType* old_ancestor_that_moves_pixels = NULL;
148 if (!stack_.empty()) { 148 if (!stack_.empty()) {
149 old_target = stack_.back().target; 149 old_target = stack_.back().target;
150 old_ancestor_that_moves_pixels = 150 old_ancestor_that_moves_pixels =
151 old_target->renderSurface()->nearest_ancestor_that_moves_pixels(); 151 old_target->render_surface()->nearest_ancestor_that_moves_pixels();
152 } 152 }
153 const RenderSurfaceType* new_ancestor_that_moves_pixels = 153 const RenderSurfaceType* new_ancestor_that_moves_pixels =
154 new_target->renderSurface()->nearest_ancestor_that_moves_pixels(); 154 new_target->render_surface()->nearest_ancestor_that_moves_pixels();
155 155
156 stack_.push_back(StackObject(new_target)); 156 stack_.push_back(StackObject(new_target));
157 157
158 // We copy the screen occlusion into the new RenderSurface subtree, but we 158 // We copy the screen occlusion into the new RenderSurface subtree, but we
159 // never copy in the occlusion from inside the target, since we are looking 159 // never copy in the occlusion from inside the target, since we are looking
160 // at a new RenderSurface target. 160 // at a new RenderSurface target.
161 161
162 // If we are entering a subtree that is going to move pixels around, then the 162 // If we are entering a subtree that is going to move pixels around, then the
163 // occlusion we've computed so far won't apply to the pixels we're drawing 163 // occlusion we've computed so far won't apply to the pixels we're drawing
164 // here in the same way. We discard the occlusion thus far to be safe, and 164 // here in the same way. We discard the occlusion thus far to be safe, and
165 // ensure we don't cull any pixels that are moved such that they become 165 // ensure we don't cull any pixels that are moved such that they become
166 // visible. 166 // visible.
167 bool entering_subtree_that_moves_pixels = 167 bool entering_subtree_that_moves_pixels =
168 new_ancestor_that_moves_pixels && 168 new_ancestor_that_moves_pixels &&
169 new_ancestor_that_moves_pixels != old_ancestor_that_moves_pixels; 169 new_ancestor_that_moves_pixels != old_ancestor_that_moves_pixels;
170 170
171 bool have_transform_from_screen_to_new_target = false; 171 bool have_transform_from_screen_to_new_target = false;
172 gfx::Transform inverse_new_target_screen_space_transform( 172 gfx::Transform inverse_new_target_screen_space_transform(
173 // Note carefully, not used if screen space transform is uninvertible. 173 // Note carefully, not used if screen space transform is uninvertible.
174 gfx::Transform::kSkipInitialization); 174 gfx::Transform::kSkipInitialization);
175 if (SurfaceTransformsToScreenKnown(new_target->renderSurface())) { 175 if (SurfaceTransformsToScreenKnown(new_target->render_surface())) {
176 have_transform_from_screen_to_new_target = 176 have_transform_from_screen_to_new_target =
177 new_target->renderSurface()->screen_space_transform().GetInverse( 177 new_target->render_surface()->screen_space_transform().GetInverse(
178 &inverse_new_target_screen_space_transform); 178 &inverse_new_target_screen_space_transform);
179 } 179 }
180 180
181 bool entering_root_target = new_target->parent() == NULL; 181 bool entering_root_target = new_target->parent() == NULL;
182 182
183 bool copy_outside_occlusion_forward = 183 bool copy_outside_occlusion_forward =
184 stack_.size() > 1 && 184 stack_.size() > 1 &&
185 !entering_subtree_that_moves_pixels && 185 !entering_subtree_that_moves_pixels &&
186 have_transform_from_screen_to_new_target && 186 have_transform_from_screen_to_new_target &&
187 !entering_root_target; 187 !entering_root_target;
188 if (!copy_outside_occlusion_forward) 188 if (!copy_outside_occlusion_forward)
189 return; 189 return;
190 190
191 int last_index = stack_.size() - 1; 191 int last_index = stack_.size() - 1;
192 gfx::Transform old_target_to_new_target_transform( 192 gfx::Transform old_target_to_new_target_transform(
193 inverse_new_target_screen_space_transform, 193 inverse_new_target_screen_space_transform,
194 old_target->renderSurface()->screen_space_transform()); 194 old_target->render_surface()->screen_space_transform());
195 stack_[last_index].occlusion_from_outside_target = 195 stack_[last_index].occlusion_from_outside_target =
196 TransformSurfaceOpaqueRegion<RenderSurfaceType>( 196 TransformSurfaceOpaqueRegion<RenderSurfaceType>(
197 stack_[last_index - 1].occlusion_from_outside_target, 197 stack_[last_index - 1].occlusion_from_outside_target,
198 false, 198 false,
199 gfx::Rect(), 199 gfx::Rect(),
200 old_target_to_new_target_transform); 200 old_target_to_new_target_transform);
201 stack_[last_index].occlusion_from_outside_target.Union( 201 stack_[last_index].occlusion_from_outside_target.Union(
202 TransformSurfaceOpaqueRegion<RenderSurfaceType>( 202 TransformSurfaceOpaqueRegion<RenderSurfaceType>(
203 stack_[last_index - 1].occlusion_from_inside_target, 203 stack_[last_index - 1].occlusion_from_inside_target,
204 false, 204 false,
205 gfx::Rect(), 205 gfx::Rect(),
206 old_target_to_new_target_transform)); 206 old_target_to_new_target_transform));
207 } 207 }
208 208
209 template <typename LayerType, typename RenderSurfaceType> 209 template <typename LayerType, typename RenderSurfaceType>
210 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget( 210 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget(
211 const LayerType* finished_target) { 211 const LayerType* finished_target) {
212 // Make sure we know about the target surface. 212 // Make sure we know about the target surface.
213 EnterRenderTarget(finished_target); 213 EnterRenderTarget(finished_target);
214 214
215 RenderSurfaceType* surface = finished_target->renderSurface(); 215 RenderSurfaceType* surface = finished_target->render_surface();
216 216
217 // If the occlusion within the surface can not be applied to things outside of 217 // If the occlusion within the surface can not be applied to things outside of
218 // the surface's subtree, then clear the occlusion here so it won't be used. 218 // the surface's subtree, then clear the occlusion here so it won't be used.
219 // TODO(senorblanco): Make this smarter for SkImageFilter case: once 219 // TODO(senorblanco): Make this smarter for SkImageFilter case: once
220 // SkImageFilters can report affectsOpacity(), call that. 220 // SkImageFilters can report affectsOpacity(), call that.
221 if (finished_target->maskLayer() || 221 if (finished_target->mask_layer() ||
222 !SurfaceOpacityKnown(surface) || 222 !SurfaceOpacityKnown(surface) ||
223 surface->draw_opacity() < 1 || 223 surface->draw_opacity() < 1 ||
224 finished_target->filters().hasFilterThatAffectsOpacity() || 224 finished_target->filters().hasFilterThatAffectsOpacity() ||
225 finished_target->filter()) { 225 finished_target->filter()) {
226 stack_.back().occlusion_from_outside_target.Clear(); 226 stack_.back().occlusion_from_outside_target.Clear();
227 stack_.back().occlusion_from_inside_target.Clear(); 227 stack_.back().occlusion_from_inside_target.Clear();
228 } else if (!SurfaceTransformsToTargetKnown(surface)) { 228 } else if (!SurfaceTransformsToTargetKnown(surface)) {
229 stack_.back().occlusion_from_inside_target.Clear(); 229 stack_.back().occlusion_from_inside_target.Clear();
230 stack_.back().occlusion_from_outside_target.Clear(); 230 stack_.back().occlusion_from_outside_target.Clear();
231 } 231 }
232 } 232 }
233 233
234 template <typename LayerType> 234 template <typename LayerType>
235 static void ReduceOcclusionBelowSurface(LayerType* contributing_layer, 235 static void ReduceOcclusionBelowSurface(LayerType* contributing_layer,
236 gfx::Rect surface_rect, 236 gfx::Rect surface_rect,
237 const gfx::Transform& surface_transform, 237 const gfx::Transform& surface_transform,
238 LayerType* render_target, 238 LayerType* render_target,
239 Region* occlusion_from_inside_target) { 239 Region* occlusion_from_inside_target) {
240 if (surface_rect.IsEmpty()) 240 if (surface_rect.IsEmpty())
241 return; 241 return;
242 242
243 gfx::Rect affected_area_in_target = gfx::ToEnclosingRect( 243 gfx::Rect affected_area_in_target = gfx::ToEnclosingRect(
244 MathUtil::mapClippedRect(surface_transform, gfx::RectF(surface_rect))); 244 MathUtil::mapClippedRect(surface_transform, gfx::RectF(surface_rect)));
245 if (contributing_layer->renderSurface()->is_clipped()) { 245 if (contributing_layer->render_surface()->is_clipped()) {
246 affected_area_in_target.Intersect( 246 affected_area_in_target.Intersect(
247 contributing_layer->renderSurface()->clip_rect()); 247 contributing_layer->render_surface()->clip_rect());
248 } 248 }
249 if (affected_area_in_target.IsEmpty()) 249 if (affected_area_in_target.IsEmpty())
250 return; 250 return;
251 251
252 int outset_top, outset_right, outset_bottom, outset_left; 252 int outset_top, outset_right, outset_bottom, outset_left;
253 contributing_layer->backgroundFilters().getOutsets( 253 contributing_layer->background_filters().getOutsets(
254 outset_top, outset_right, outset_bottom, outset_left); 254 outset_top, outset_right, outset_bottom, outset_left);
255 255
256 // The filter can move pixels from outside of the clip, so allow affectedArea 256 // The filter can move pixels from outside of the clip, so allow affectedArea
257 // to expand outside the clip. 257 // to expand outside the clip.
258 affected_area_in_target.Inset( 258 affected_area_in_target.Inset(
259 -outset_left, -outset_top, -outset_right, -outset_bottom); 259 -outset_left, -outset_top, -outset_right, -outset_bottom);
260 260
261 gfx::Rect FilterOutsetsInTarget(-outset_left, 261 gfx::Rect FilterOutsetsInTarget(-outset_left,
262 -outset_top, 262 -outset_top,
263 outset_left + outset_right, 263 outset_left + outset_right,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 const LayerType* new_target) { 297 const LayerType* new_target) {
298 int last_index = stack_.size() - 1; 298 int last_index = stack_.size() - 1;
299 bool surface_will_be_at_top_after_pop = 299 bool surface_will_be_at_top_after_pop =
300 stack_.size() > 1 && stack_[last_index - 1].target == new_target; 300 stack_.size() > 1 && stack_[last_index - 1].target == new_target;
301 301
302 // We merge the screen occlusion from the current RenderSurfaceImpl subtree 302 // We merge the screen occlusion from the current RenderSurfaceImpl subtree
303 // out to its parent target RenderSurfaceImpl. The target occlusion can be 303 // out to its parent target RenderSurfaceImpl. The target occlusion can be
304 // merged out as well but needs to be transformed to the new target. 304 // merged out as well but needs to be transformed to the new target.
305 305
306 const LayerType* old_target = stack_[last_index].target; 306 const LayerType* old_target = stack_[last_index].target;
307 const RenderSurfaceType* old_surface = old_target->renderSurface(); 307 const RenderSurfaceType* old_surface = old_target->render_surface();
308 308
309 Region old_occlusion_from_inside_target_in_new_target = 309 Region old_occlusion_from_inside_target_in_new_target =
310 TransformSurfaceOpaqueRegion<RenderSurfaceType>( 310 TransformSurfaceOpaqueRegion<RenderSurfaceType>(
311 stack_[last_index].occlusion_from_inside_target, 311 stack_[last_index].occlusion_from_inside_target,
312 old_surface->is_clipped(), 312 old_surface->is_clipped(),
313 old_surface->clip_rect(), 313 old_surface->clip_rect(),
314 old_surface->draw_transform()); 314 old_surface->draw_transform());
315 if (old_target->hasReplica() && !old_target->replicaHasMask()) { 315 if (old_target->has_replica() && !old_target->replica_has_mask()) {
316 old_occlusion_from_inside_target_in_new_target.Union( 316 old_occlusion_from_inside_target_in_new_target.Union(
317 TransformSurfaceOpaqueRegion<RenderSurfaceType>( 317 TransformSurfaceOpaqueRegion<RenderSurfaceType>(
318 stack_[last_index].occlusion_from_inside_target, 318 stack_[last_index].occlusion_from_inside_target,
319 old_surface->is_clipped(), 319 old_surface->is_clipped(),
320 old_surface->clip_rect(), 320 old_surface->clip_rect(),
321 old_surface->replica_draw_transform())); 321 old_surface->replica_draw_transform()));
322 } 322 }
323 323
324 Region old_occlusion_from_outside_target_in_new_target = 324 Region old_occlusion_from_outside_target_in_new_target =
325 TransformSurfaceOpaqueRegion<RenderSurfaceType>( 325 TransformSurfaceOpaqueRegion<RenderSurfaceType>(
326 stack_[last_index].occlusion_from_outside_target, 326 stack_[last_index].occlusion_from_outside_target,
327 false, 327 false,
328 gfx::Rect(), 328 gfx::Rect(),
329 old_surface->draw_transform()); 329 old_surface->draw_transform());
330 330
331 gfx::Rect unoccluded_surface_rect; 331 gfx::Rect unoccluded_surface_rect;
332 gfx::Rect unoccluded_replica_rect; 332 gfx::Rect unoccluded_replica_rect;
333 if (old_target->backgroundFilters().hasFilterThatMovesPixels()) { 333 if (old_target->background_filters().hasFilterThatMovesPixels()) {
334 unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect( 334 unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect(
335 old_target, false, old_surface->content_rect(), NULL); 335 old_target, false, old_surface->content_rect(), NULL);
336 if (old_target->hasReplica()) { 336 if (old_target->has_replica()) {
337 unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect( 337 unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect(
338 old_target, true, old_surface->content_rect(), NULL); 338 old_target, true, old_surface->content_rect(), NULL);
339 } 339 }
340 } 340 }
341 341
342 if (surface_will_be_at_top_after_pop) { 342 if (surface_will_be_at_top_after_pop) {
343 // Merge the top of the stack down. 343 // Merge the top of the stack down.
344 stack_[last_index - 1].occlusion_from_inside_target.Union( 344 stack_[last_index - 1].occlusion_from_inside_target.Union(
345 old_occlusion_from_inside_target_in_new_target); 345 old_occlusion_from_inside_target_in_new_target);
346 // TODO(danakj): Strictly this should subtract the inside target occlusion 346 // TODO(danakj): Strictly this should subtract the inside target occlusion
347 // before union. 347 // before union.
348 if (new_target->parent()) { 348 if (new_target->parent()) {
349 stack_[last_index - 1].occlusion_from_outside_target.Union( 349 stack_[last_index - 1].occlusion_from_outside_target.Union(
350 old_occlusion_from_outside_target_in_new_target); 350 old_occlusion_from_outside_target_in_new_target);
351 } 351 }
352 stack_.pop_back(); 352 stack_.pop_back();
353 } else { 353 } else {
354 // Replace the top of the stack with the new pushed surface. 354 // Replace the top of the stack with the new pushed surface.
355 stack_.back().target = new_target; 355 stack_.back().target = new_target;
356 stack_.back().occlusion_from_inside_target = 356 stack_.back().occlusion_from_inside_target =
357 old_occlusion_from_inside_target_in_new_target; 357 old_occlusion_from_inside_target_in_new_target;
358 if (new_target->parent()) { 358 if (new_target->parent()) {
359 stack_.back().occlusion_from_outside_target = 359 stack_.back().occlusion_from_outside_target =
360 old_occlusion_from_outside_target_in_new_target; 360 old_occlusion_from_outside_target_in_new_target;
361 } else { 361 } else {
362 stack_.back().occlusion_from_outside_target.Clear(); 362 stack_.back().occlusion_from_outside_target.Clear();
363 } 363 }
364 } 364 }
365 365
366 if (!old_target->backgroundFilters().hasFilterThatMovesPixels()) 366 if (!old_target->background_filters().hasFilterThatMovesPixels())
367 return; 367 return;
368 368
369 ReduceOcclusionBelowSurface(old_target, 369 ReduceOcclusionBelowSurface(old_target,
370 unoccluded_surface_rect, 370 unoccluded_surface_rect,
371 old_surface->draw_transform(), 371 old_surface->draw_transform(),
372 new_target, 372 new_target,
373 &stack_.back().occlusion_from_inside_target); 373 &stack_.back().occlusion_from_inside_target);
374 ReduceOcclusionBelowSurface(old_target, 374 ReduceOcclusionBelowSurface(old_target,
375 unoccluded_surface_rect, 375 unoccluded_surface_rect,
376 old_surface->draw_transform(), 376 old_surface->draw_transform(),
377 new_target, 377 new_target,
378 &stack_.back().occlusion_from_outside_target); 378 &stack_.back().occlusion_from_outside_target);
379 379
380 if (!old_target->hasReplica()) 380 if (!old_target->has_replica())
381 return; 381 return;
382 ReduceOcclusionBelowSurface(old_target, 382 ReduceOcclusionBelowSurface(old_target,
383 unoccluded_replica_rect, 383 unoccluded_replica_rect,
384 old_surface->replica_draw_transform(), 384 old_surface->replica_draw_transform(),
385 new_target, 385 new_target,
386 &stack_.back().occlusion_from_inside_target); 386 &stack_.back().occlusion_from_inside_target);
387 ReduceOcclusionBelowSurface(old_target, 387 ReduceOcclusionBelowSurface(old_target,
388 unoccluded_replica_rect, 388 unoccluded_replica_rect,
389 old_surface->replica_draw_transform(), 389 old_surface->replica_draw_transform(),
390 new_target, 390 new_target,
391 &stack_.back().occlusion_from_outside_target); 391 &stack_.back().occlusion_from_outside_target);
392 } 392 }
393 393
394 template <typename LayerType, typename RenderSurfaceType> 394 template <typename LayerType, typename RenderSurfaceType>
395 void OcclusionTrackerBase<LayerType, RenderSurfaceType>:: 395 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::
396 MarkOccludedBehindLayer(const LayerType* layer) { 396 MarkOccludedBehindLayer(const LayerType* layer) {
397 DCHECK(!stack_.empty()); 397 DCHECK(!stack_.empty());
398 DCHECK_EQ(layer->renderTarget(), stack_.back().target); 398 DCHECK_EQ(layer->render_target(), stack_.back().target);
399 if (stack_.empty()) 399 if (stack_.empty())
400 return; 400 return;
401 401
402 if (!LayerOpacityKnown(layer) || layer->drawOpacity() < 1) 402 if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1)
403 return; 403 return;
404 404
405 if (LayerIsInUnsorted3dRenderingContext(layer)) 405 if (LayerIsInUnsorted3dRenderingContext(layer))
406 return; 406 return;
407 407
408 if (!LayerTransformsToTargetKnown(layer)) 408 if (!LayerTransformsToTargetKnown(layer))
409 return; 409 return;
410 410
411 Region opaque_contents = layer->visibleContentOpaqueRegion(); 411 Region opaque_contents = layer->VisibleContentOpaqueRegion();
412 if (opaque_contents.IsEmpty()) 412 if (opaque_contents.IsEmpty())
413 return; 413 return;
414 414
415 DCHECK(layer->visibleContentRect().Contains(opaque_contents.bounds())); 415 DCHECK(layer->visible_content_rect().Contains(opaque_contents.bounds()));
416 416
417 bool clipped; 417 bool clipped;
418 gfx::QuadF visible_transformed_quad = MathUtil::mapQuad( 418 gfx::QuadF visible_transformed_quad = MathUtil::mapQuad(
419 layer->drawTransform(), gfx::QuadF(opaque_contents.bounds()), clipped); 419 layer->draw_transform(), gfx::QuadF(opaque_contents.bounds()), clipped);
420 // FIXME: Find a rect interior to each transformed quad. 420 // FIXME: Find a rect interior to each transformed quad.
421 if (clipped || !visible_transformed_quad.IsRectilinear()) 421 if (clipped || !visible_transformed_quad.IsRectilinear())
422 return; 422 return;
423 423
424 gfx::Rect clip_rect_in_target = gfx::IntersectRects( 424 gfx::Rect clip_rect_in_target = gfx::IntersectRects(
425 layer->renderTarget()->renderSurface()->content_rect(), 425 layer->render_target()->render_surface()->content_rect(),
426 ScreenSpaceClipRectInTargetSurface( 426 ScreenSpaceClipRectInTargetSurface(
427 layer->renderTarget()->renderSurface(), screen_space_clip_rect_)); 427 layer->render_target()->render_surface(), screen_space_clip_rect_));
428 428
429 for (Region::Iterator opaqueContentRects(opaque_contents); 429 for (Region::Iterator opaqueContentRects(opaque_contents);
430 opaqueContentRects.has_rect(); 430 opaqueContentRects.has_rect();
431 opaqueContentRects.next()) { 431 opaqueContentRects.next()) {
432 gfx::QuadF transformed_quad = MathUtil::mapQuad( 432 gfx::QuadF transformed_quad = MathUtil::mapQuad(
433 layer->drawTransform(), 433 layer->draw_transform(),
434 gfx::QuadF(opaqueContentRects.rect()), 434 gfx::QuadF(opaqueContentRects.rect()),
435 clipped); 435 clipped);
436 gfx::Rect transformed_rect = 436 gfx::Rect transformed_rect =
437 gfx::ToEnclosedRect(transformed_quad.BoundingBox()); 437 gfx::ToEnclosedRect(transformed_quad.BoundingBox());
438 DCHECK(!clipped); // We only map if the transform preserves axis alignment. 438 DCHECK(!clipped); // We only map if the transform preserves axis alignment.
439 transformed_rect.Intersect(clip_rect_in_target); 439 transformed_rect.Intersect(clip_rect_in_target);
440 if (transformed_rect.width() < minimum_tracking_size_.width() && 440 if (transformed_rect.width() < minimum_tracking_size_.width() &&
441 transformed_rect.height() < minimum_tracking_size_.height()) 441 transformed_rect.height() < minimum_tracking_size_.height())
442 continue; 442 continue;
443 stack_.back().occlusion_from_inside_target.Union(transformed_rect); 443 stack_.back().occlusion_from_inside_target.Union(transformed_rect);
444 444
445 if (!occluding_screen_space_rects_) 445 if (!occluding_screen_space_rects_)
446 continue; 446 continue;
447 447
448 // Save the occluding area in screen space for debug visualization. 448 // Save the occluding area in screen space for debug visualization.
449 gfx::QuadF screen_space_quad = MathUtil::mapQuad( 449 gfx::QuadF screen_space_quad = MathUtil::mapQuad(
450 layer->renderTarget()->renderSurface()->screen_space_transform(), 450 layer->render_target()->render_surface()->screen_space_transform(),
451 gfx::QuadF(transformed_rect), clipped); 451 gfx::QuadF(transformed_rect), clipped);
452 // TODO(danakj): Store the quad in the debug info instead of the bounding 452 // TODO(danakj): Store the quad in the debug info instead of the bounding
453 // box. 453 // box.
454 gfx::Rect screen_space_rect = 454 gfx::Rect screen_space_rect =
455 gfx::ToEnclosedRect(screen_space_quad.BoundingBox()); 455 gfx::ToEnclosedRect(screen_space_quad.BoundingBox());
456 occluding_screen_space_rects_->push_back(screen_space_rect); 456 occluding_screen_space_rects_->push_back(screen_space_rect);
457 } 457 }
458 458
459 if (!non_occluding_screen_space_rects_) 459 if (!non_occluding_screen_space_rects_)
460 return; 460 return;
461 461
462 Region non_opaque_contents = 462 Region non_opaque_contents =
463 SubtractRegions(gfx::Rect(layer->contentBounds()), opaque_contents); 463 SubtractRegions(gfx::Rect(layer->content_bounds()), opaque_contents);
464 for (Region::Iterator nonOpaqueContentRects(non_opaque_contents); 464 for (Region::Iterator nonOpaqueContentRects(non_opaque_contents);
465 nonOpaqueContentRects.has_rect(); 465 nonOpaqueContentRects.has_rect();
466 nonOpaqueContentRects.next()) { 466 nonOpaqueContentRects.next()) {
467 // We've already checked for clipping in the mapQuad call above, these calls 467 // We've already checked for clipping in the mapQuad call above, these calls
468 // should not clip anything further. 468 // should not clip anything further.
469 gfx::Rect transformed_rect = gfx::ToEnclosedRect( 469 gfx::Rect transformed_rect = gfx::ToEnclosedRect(
470 MathUtil::mapClippedRect(layer->drawTransform(), 470 MathUtil::mapClippedRect(layer->draw_transform(),
471 gfx::RectF(nonOpaqueContentRects.rect()))); 471 gfx::RectF(nonOpaqueContentRects.rect())));
472 transformed_rect.Intersect(clip_rect_in_target); 472 transformed_rect.Intersect(clip_rect_in_target);
473 if (transformed_rect.IsEmpty()) 473 if (transformed_rect.IsEmpty())
474 continue; 474 continue;
475 475
476 gfx::QuadF screen_space_quad = MathUtil::mapQuad( 476 gfx::QuadF screen_space_quad = MathUtil::mapQuad(
477 layer->renderTarget()->renderSurface()->screen_space_transform(), 477 layer->render_target()->render_surface()->screen_space_transform(),
478 gfx::QuadF(transformed_rect), 478 gfx::QuadF(transformed_rect),
479 clipped); 479 clipped);
480 // TODO(danakj): Store the quad in the debug info instead of the bounding 480 // TODO(danakj): Store the quad in the debug info instead of the bounding
481 // box. 481 // box.
482 gfx::Rect screen_space_rect = 482 gfx::Rect screen_space_rect =
483 gfx::ToEnclosedRect(screen_space_quad.BoundingBox()); 483 gfx::ToEnclosedRect(screen_space_quad.BoundingBox());
484 non_occluding_screen_space_rects_->push_back(screen_space_rect); 484 non_occluding_screen_space_rects_->push_back(screen_space_rect);
485 } 485 }
486 } 486 }
487 487
(...skipping 14 matching lines...) Expand all
502 return false; 502 return false;
503 if (content_rect.IsEmpty()) 503 if (content_rect.IsEmpty())
504 return true; 504 return true;
505 if (impl_draw_transform_is_unknown) 505 if (impl_draw_transform_is_unknown)
506 return false; 506 return false;
507 507
508 // For tests with no render target. 508 // For tests with no render target.
509 if (!render_target) 509 if (!render_target)
510 return false; 510 return false;
511 511
512 DCHECK_EQ(render_target->renderTarget(), render_target); 512 DCHECK_EQ(render_target->render_target(), render_target);
513 DCHECK(render_target->renderSurface()); 513 DCHECK(render_target->render_surface());
514 DCHECK_EQ(render_target, stack_.back().target); 514 DCHECK_EQ(render_target, stack_.back().target);
515 515
516 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); 516 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
517 if (!draw_transform.GetInverse(&inverse_draw_transform)) 517 if (!draw_transform.GetInverse(&inverse_draw_transform))
518 return false; 518 return false;
519 519
520 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded 520 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
521 // partial pixels in the resulting Rect. 521 // partial pixels in the resulting Rect.
522 Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect( 522 Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect(
523 MathUtil::mapClippedRect(draw_transform, gfx::RectF(content_rect))); 523 MathUtil::mapClippedRect(draw_transform, gfx::RectF(content_rect)));
524 // Layers can't clip across surfaces, so count this as internal occlusion. 524 // Layers can't clip across surfaces, so count this as internal occlusion.
525 if (is_clipped) 525 if (is_clipped)
526 unoccluded_region_in_target_surface.Intersect(clip_rect_in_target); 526 unoccluded_region_in_target_surface.Intersect(clip_rect_in_target);
527 unoccluded_region_in_target_surface.Subtract( 527 unoccluded_region_in_target_surface.Subtract(
528 stack_.back().occlusion_from_inside_target); 528 stack_.back().occlusion_from_inside_target);
529 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion = 529 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion =
530 unoccluded_region_in_target_surface.bounds(); 530 unoccluded_region_in_target_surface.bounds();
531 unoccluded_region_in_target_surface.Subtract( 531 unoccluded_region_in_target_surface.Subtract(
532 stack_.back().occlusion_from_outside_target); 532 stack_.back().occlusion_from_outside_target);
533 533
534 // Treat other clipping as occlusion from outside the surface. 534 // Treat other clipping as occlusion from outside the surface.
535 // TODO(danakj): Clip to visibleContentRect? 535 // TODO(danakj): Clip to visibleContentRect?
536 unoccluded_region_in_target_surface.Intersect( 536 unoccluded_region_in_target_surface.Intersect(
537 render_target->renderSurface()->content_rect()); 537 render_target->render_surface()->content_rect());
538 unoccluded_region_in_target_surface.Intersect( 538 unoccluded_region_in_target_surface.Intersect(
539 ScreenSpaceClipRectInTargetSurface(render_target->renderSurface(), 539 ScreenSpaceClipRectInTargetSurface(render_target->render_surface(),
540 screen_space_clip_rect_)); 540 screen_space_clip_rect_));
541 541
542 gfx::RectF unoccluded_rect_in_target_surface = 542 gfx::RectF unoccluded_rect_in_target_surface =
543 unoccluded_region_in_target_surface.bounds(); 543 unoccluded_region_in_target_surface.bounds();
544 544
545 if (has_occlusion_from_outside_target_surface) { 545 if (has_occlusion_from_outside_target_surface) {
546 // Check if the unoccluded rect shrank when applying outside occlusion. 546 // Check if the unoccluded rect shrank when applying outside occlusion.
547 *has_occlusion_from_outside_target_surface = !gfx::SubtractRects( 547 *has_occlusion_from_outside_target_surface = !gfx::SubtractRects(
548 unoccluded_rect_in_target_surface_without_outside_occlusion, 548 unoccluded_rect_in_target_surface_without_outside_occlusion,
549 unoccluded_rect_in_target_surface).IsEmpty(); 549 unoccluded_rect_in_target_surface).IsEmpty();
(...skipping 20 matching lines...) Expand all
570 return content_rect; 570 return content_rect;
571 if (content_rect.IsEmpty()) 571 if (content_rect.IsEmpty())
572 return content_rect; 572 return content_rect;
573 if (impl_draw_transform_is_unknown) 573 if (impl_draw_transform_is_unknown)
574 return content_rect; 574 return content_rect;
575 575
576 // For tests with no render target. 576 // For tests with no render target.
577 if (!render_target) 577 if (!render_target)
578 return content_rect; 578 return content_rect;
579 579
580 DCHECK_EQ(render_target->renderTarget(), render_target); 580 DCHECK_EQ(render_target->render_target(), render_target);
581 DCHECK(render_target->renderSurface()); 581 DCHECK(render_target->render_surface());
582 DCHECK_EQ(render_target, stack_.back().target); 582 DCHECK_EQ(render_target, stack_.back().target);
583 583
584 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); 584 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
585 if (!draw_transform.GetInverse(&inverse_draw_transform)) 585 if (!draw_transform.GetInverse(&inverse_draw_transform))
586 return content_rect; 586 return content_rect;
587 587
588 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded 588 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
589 // partial pixels in the resulting Rect. 589 // partial pixels in the resulting Rect.
590 Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect( 590 Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect(
591 MathUtil::mapClippedRect(draw_transform, gfx::RectF(content_rect))); 591 MathUtil::mapClippedRect(draw_transform, gfx::RectF(content_rect)));
592 // Layers can't clip across surfaces, so count this as internal occlusion. 592 // Layers can't clip across surfaces, so count this as internal occlusion.
593 if (is_clipped) 593 if (is_clipped)
594 unoccluded_region_in_target_surface.Intersect(clip_rect_in_target); 594 unoccluded_region_in_target_surface.Intersect(clip_rect_in_target);
595 unoccluded_region_in_target_surface.Subtract( 595 unoccluded_region_in_target_surface.Subtract(
596 stack_.back().occlusion_from_inside_target); 596 stack_.back().occlusion_from_inside_target);
597 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion = 597 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion =
598 unoccluded_region_in_target_surface.bounds(); 598 unoccluded_region_in_target_surface.bounds();
599 unoccluded_region_in_target_surface.Subtract( 599 unoccluded_region_in_target_surface.Subtract(
600 stack_.back().occlusion_from_outside_target); 600 stack_.back().occlusion_from_outside_target);
601 601
602 // Treat other clipping as occlusion from outside the surface. 602 // Treat other clipping as occlusion from outside the surface.
603 // TODO(danakj): Clip to visibleContentRect? 603 // TODO(danakj): Clip to visibleContentRect?
604 unoccluded_region_in_target_surface.Intersect( 604 unoccluded_region_in_target_surface.Intersect(
605 render_target->renderSurface()->content_rect()); 605 render_target->render_surface()->content_rect());
606 unoccluded_region_in_target_surface.Intersect( 606 unoccluded_region_in_target_surface.Intersect(
607 ScreenSpaceClipRectInTargetSurface(render_target->renderSurface(), 607 ScreenSpaceClipRectInTargetSurface(render_target->render_surface(),
608 screen_space_clip_rect_)); 608 screen_space_clip_rect_));
609 609
610 gfx::RectF unoccluded_rect_in_target_surface = 610 gfx::RectF unoccluded_rect_in_target_surface =
611 unoccluded_region_in_target_surface.bounds(); 611 unoccluded_region_in_target_surface.bounds();
612 gfx::Rect unoccluded_rect = gfx::ToEnclosingRect( 612 gfx::Rect unoccluded_rect = gfx::ToEnclosingRect(
613 MathUtil::projectClippedRect(inverse_draw_transform, 613 MathUtil::projectClippedRect(inverse_draw_transform,
614 unoccluded_rect_in_target_surface)); 614 unoccluded_rect_in_target_surface));
615 unoccluded_rect.Intersect(content_rect); 615 unoccluded_rect.Intersect(content_rect);
616 616
617 if (has_occlusion_from_outside_target_surface) { 617 if (has_occlusion_from_outside_target_surface) {
618 // Check if the unoccluded rect shrank when applying outside occlusion. 618 // Check if the unoccluded rect shrank when applying outside occlusion.
619 *has_occlusion_from_outside_target_surface = !gfx::SubtractRects( 619 *has_occlusion_from_outside_target_surface = !gfx::SubtractRects(
620 unoccluded_rect_in_target_surface_without_outside_occlusion, 620 unoccluded_rect_in_target_surface_without_outside_occlusion,
621 unoccluded_rect_in_target_surface).IsEmpty(); 621 unoccluded_rect_in_target_surface).IsEmpty();
622 } 622 }
623 623
624 return unoccluded_rect; 624 return unoccluded_rect;
625 } 625 }
626 626
627 template <typename LayerType, typename RenderSurfaceType> 627 template <typename LayerType, typename RenderSurfaceType>
628 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>:: 628 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::
629 UnoccludedContributingSurfaceContentRect( 629 UnoccludedContributingSurfaceContentRect(
630 const LayerType* layer, 630 const LayerType* layer,
631 bool for_replica, 631 bool for_replica,
632 gfx::Rect content_rect, 632 gfx::Rect content_rect,
633 bool* has_occlusion_from_outside_target_surface) const { 633 bool* has_occlusion_from_outside_target_surface) const {
634 DCHECK(!stack_.empty()); 634 DCHECK(!stack_.empty());
635 // The layer is a contributing render_target so it should have a surface. 635 // The layer is a contributing render_target so it should have a surface.
636 DCHECK(layer->renderSurface()); 636 DCHECK(layer->render_surface());
637 // The layer is a contributing render_target so its target should be itself. 637 // The layer is a contributing render_target so its target should be itself.
638 DCHECK_EQ(layer->renderTarget(), layer); 638 DCHECK_EQ(layer->render_target(), layer);
639 // The layer should not be the root, else what is is contributing to? 639 // The layer should not be the root, else what is is contributing to?
640 DCHECK(layer->parent()); 640 DCHECK(layer->parent());
641 // This should be called while the layer is still considered the current 641 // This should be called while the layer is still considered the current
642 // target in the occlusion tracker. 642 // target in the occlusion tracker.
643 DCHECK_EQ(layer, stack_.back().target); 643 DCHECK_EQ(layer, stack_.back().target);
644 644
645 if (has_occlusion_from_outside_target_surface) 645 if (has_occlusion_from_outside_target_surface)
646 *has_occlusion_from_outside_target_surface = false; 646 *has_occlusion_from_outside_target_surface = false;
647 647
648 if (content_rect.IsEmpty()) 648 if (content_rect.IsEmpty())
649 return content_rect; 649 return content_rect;
650 650
651 const RenderSurfaceType* surface = layer->renderSurface(); 651 const RenderSurfaceType* surface = layer->render_surface();
652 const LayerType* contributing_surface_render_target = 652 const LayerType* contributing_surface_render_target =
653 layer->parent()->renderTarget(); 653 layer->parent()->render_target();
654 654
655 if (!SurfaceTransformsToTargetKnown(surface)) 655 if (!SurfaceTransformsToTargetKnown(surface))
656 return content_rect; 656 return content_rect;
657 657
658 gfx::Transform draw_transform = 658 gfx::Transform draw_transform =
659 for_replica ? surface->replica_draw_transform() : surface->draw_transform( ); 659 for_replica ? surface->replica_draw_transform() : surface->draw_transform( );
660 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); 660 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
661 if (!draw_transform.GetInverse(&inverse_draw_transform)) 661 if (!draw_transform.GetInverse(&inverse_draw_transform))
662 return content_rect; 662 return content_rect;
663 663
(...skipping 17 matching lines...) Expand all
681 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion = 681 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion =
682 unoccluded_region_in_target_surface.bounds(); 682 unoccluded_region_in_target_surface.bounds();
683 if (has_occlusion) { 683 if (has_occlusion) {
684 const StackObject& second_last = stack_[stack_.size() - 2]; 684 const StackObject& second_last = stack_[stack_.size() - 2];
685 unoccluded_region_in_target_surface.Subtract( 685 unoccluded_region_in_target_surface.Subtract(
686 second_last.occlusion_from_outside_target); 686 second_last.occlusion_from_outside_target);
687 } 687 }
688 688
689 // Treat other clipping as occlusion from outside the target surface. 689 // Treat other clipping as occlusion from outside the target surface.
690 unoccluded_region_in_target_surface.Intersect( 690 unoccluded_region_in_target_surface.Intersect(
691 contributing_surface_render_target->renderSurface()->content_rect()); 691 contributing_surface_render_target->render_surface()->content_rect());
692 unoccluded_region_in_target_surface.Intersect( 692 unoccluded_region_in_target_surface.Intersect(
693 ScreenSpaceClipRectInTargetSurface( 693 ScreenSpaceClipRectInTargetSurface(
694 contributing_surface_render_target->renderSurface(), 694 contributing_surface_render_target->render_surface(),
695 screen_space_clip_rect_)); 695 screen_space_clip_rect_));
696 696
697 gfx::RectF unoccluded_rect_in_target_surface = 697 gfx::RectF unoccluded_rect_in_target_surface =
698 unoccluded_region_in_target_surface.bounds(); 698 unoccluded_region_in_target_surface.bounds();
699 gfx::Rect unoccluded_rect = gfx::ToEnclosingRect( 699 gfx::Rect unoccluded_rect = gfx::ToEnclosingRect(
700 MathUtil::projectClippedRect(inverse_draw_transform, 700 MathUtil::projectClippedRect(inverse_draw_transform,
701 unoccluded_rect_in_target_surface)); 701 unoccluded_rect_in_target_surface));
702 unoccluded_rect.Intersect(content_rect); 702 unoccluded_rect.Intersect(content_rect);
703 703
704 if (has_occlusion_from_outside_target_surface) { 704 if (has_occlusion_from_outside_target_surface) {
705 // Check if the unoccluded rect shrank when applying outside occlusion. 705 // Check if the unoccluded rect shrank when applying outside occlusion.
706 *has_occlusion_from_outside_target_surface = !gfx::SubtractRects( 706 *has_occlusion_from_outside_target_surface = !gfx::SubtractRects(
707 unoccluded_rect_in_target_surface_without_outside_occlusion, 707 unoccluded_rect_in_target_surface_without_outside_occlusion,
708 unoccluded_rect_in_target_surface).IsEmpty(); 708 unoccluded_rect_in_target_surface).IsEmpty();
709 } 709 }
710 710
711 return unoccluded_rect; 711 return unoccluded_rect;
712 } 712 }
713 713
714 // Instantiate (and export) templates here for the linker. 714 // Instantiate (and export) templates here for the linker.
715 template class OcclusionTrackerBase<Layer, RenderSurface>; 715 template class OcclusionTrackerBase<Layer, RenderSurface>;
716 template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>; 716 template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>;
717 717
718 } // namespace cc 718 } // namespace cc
OLDNEW
« no previous file with comments | « cc/nine_patch_layer_unittest.cc ('k') | cc/occlusion_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698