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

Side by Side Diff: cc/trees/layer_tree_impl.cc

Issue 1973083002: Use element id's for animations (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 5 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
OLDNEW
1 // Copyright 2011 The Chromium Authors. All rights reserved. 1 // Copyright 2011 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/trees/layer_tree_impl.h" 5 #include "cc/trees/layer_tree_impl.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 } 476 }
477 477
478 LayerImplList::reverse_iterator LayerTreeImpl::rbegin() { 478 LayerImplList::reverse_iterator LayerTreeImpl::rbegin() {
479 return layer_list_.rbegin(); 479 return layer_list_.rbegin();
480 } 480 }
481 481
482 LayerImplList::reverse_iterator LayerTreeImpl::rend() { 482 LayerImplList::reverse_iterator LayerTreeImpl::rend() {
483 return layer_list_.rend(); 483 return layer_list_.rend();
484 } 484 }
485 485
486 LayerImpl* LayerTreeImpl::LayerByElementId(ElementId element_id) const {
487 auto iter = element_layers_map_.find(element_id);
488 if (iter == element_layers_map_.end())
489 return nullptr;
490
491 return iter->second;
492 }
493
486 void LayerTreeImpl::AddToElementMap(LayerImpl* layer) { 494 void LayerTreeImpl::AddToElementMap(LayerImpl* layer) {
487 if (!layer->element_id() || !layer->mutable_properties()) 495 if (!layer->element_id())
488 return; 496 return;
489 497
490 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), 498 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
491 "LayerTreeImpl::AddToElementMap", "element_id", 499 "LayerTreeImpl::AddToElementMap", "element",
492 layer->element_id(), "layer_id", layer->id()); 500 layer->element_id().AsValue().release(), "layer_id",
501 layer->id());
493 502
494 ElementLayers& layers = element_layers_map_[layer->element_id()]; 503 element_layers_map_[layer->element_id()] = layer;
495 if ((!layers.main || layer->IsActive()) && !layer->scrollable()) { 504
496 layers.main = layer; 505 layer_tree_host_impl_->animation_host()->RegisterElement(
497 } else if ((!layers.scroll || layer->IsActive()) && layer->scrollable()) { 506 layer->element_id(),
498 TRACE_EVENT2("compositor-worker", "LayerTreeImpl::AddToElementMap scroll", 507 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING);
499 "element_id", layer->element_id(), "layer_id", layer->id());
500 layers.scroll = layer;
501 }
502 } 508 }
503 509
504 void LayerTreeImpl::RemoveFromElementMap(LayerImpl* layer) { 510 void LayerTreeImpl::RemoveFromElementMap(LayerImpl* layer) {
505 if (!layer->element_id()) 511 if (!layer->element_id())
506 return; 512 return;
507 513
508 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), 514 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
509 "LayerTreeImpl::RemoveFromElementMap", "element_id", 515 "LayerTreeImpl::RemoveFromElementMap", "element",
510 layer->element_id(), "layer_id", layer->id()); 516 layer->element_id().AsValue().release(), "layer_id",
517 layer->id());
511 518
512 ElementLayers& layers = element_layers_map_[layer->element_id()]; 519 layer_tree_host_impl_->animation_host()->UnregisterElement(
513 if (!layer->scrollable()) 520 layer->element_id(),
514 layers.main = nullptr; 521 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING);
515 if (layer->scrollable())
516 layers.scroll = nullptr;
517 522
518 if (!layers.main && !layers.scroll) 523 element_layers_map_.erase(layer->element_id());
519 element_layers_map_.erase(layer->element_id());
520 } 524 }
521 525
522 void LayerTreeImpl::AddToOpacityAnimationsMap(int id, float opacity) { 526 void LayerTreeImpl::AddToOpacityAnimationsMap(int id, float opacity) {
523 opacity_animations_map_[id] = opacity; 527 opacity_animations_map_[id] = opacity;
524 } 528 }
525 529
526 void LayerTreeImpl::AddToTransformAnimationsMap(int id, 530 void LayerTreeImpl::AddToTransformAnimationsMap(int id,
527 gfx::Transform transform) { 531 gfx::Transform transform) {
528 transform_animations_map_[id] = transform; 532 transform_animations_map_[id] = transform;
529 } 533 }
530 534
531 LayerTreeImpl::ElementLayers LayerTreeImpl::GetMutableLayers(
532 uint64_t element_id) {
533 auto iter = element_layers_map_.find(element_id);
534 if (iter == element_layers_map_.end())
535 return ElementLayers();
536
537 return iter->second;
538 }
539
540 LayerImpl* LayerTreeImpl::InnerViewportContainerLayer() const { 535 LayerImpl* LayerTreeImpl::InnerViewportContainerLayer() const {
541 return InnerViewportScrollLayer() 536 return InnerViewportScrollLayer()
542 ? InnerViewportScrollLayer()->scroll_clip_layer() 537 ? InnerViewportScrollLayer()->scroll_clip_layer()
543 : NULL; 538 : NULL;
544 } 539 }
545 540
546 LayerImpl* LayerTreeImpl::OuterViewportContainerLayer() const { 541 LayerImpl* LayerTreeImpl::OuterViewportContainerLayer() const {
547 return OuterViewportScrollLayer() 542 return OuterViewportScrollLayer()
548 ? OuterViewportScrollLayer()->scroll_clip_layer() 543 ? OuterViewportScrollLayer()->scroll_clip_layer()
549 : NULL; 544 : NULL;
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 outer_viewport_scroll_layer_id_ = outer_viewport_scroll_layer_id; 832 outer_viewport_scroll_layer_id_ = outer_viewport_scroll_layer_id;
838 } 833 }
839 834
840 void LayerTreeImpl::ClearViewportLayers() { 835 void LayerTreeImpl::ClearViewportLayers() {
841 overscroll_elasticity_layer_id_ = Layer::INVALID_ID; 836 overscroll_elasticity_layer_id_ = Layer::INVALID_ID;
842 page_scale_layer_id_ = Layer::INVALID_ID; 837 page_scale_layer_id_ = Layer::INVALID_ID;
843 inner_viewport_scroll_layer_id_ = Layer::INVALID_ID; 838 inner_viewport_scroll_layer_id_ = Layer::INVALID_ID;
844 outer_viewport_scroll_layer_id_ = Layer::INVALID_ID; 839 outer_viewport_scroll_layer_id_ = Layer::INVALID_ID;
845 } 840 }
846 841
842 // For unit tests, we use the layer's id as its element id.
843 static void SetElementIdForTesting(LayerImpl* layer) {
844 layer->SetElementId(LayerIdToElementIdForTesting(layer->id()));
845 }
846
847 void LayerTreeImpl::SetElementIdsForTesting() {
848 LayerListIterator<LayerImpl> it(root_layer_);
849 for (; it != LayerListIterator<LayerImpl>(nullptr); ++it) {
Ian Vollick 2016/06/29 15:22:11 This is another noteworthy change. Now that "call
850 SetElementIdForTesting(*it);
851 }
852 }
853
847 bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) { 854 bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
848 if (!needs_update_draw_properties_) 855 if (!needs_update_draw_properties_)
849 return true; 856 return true;
850 857
851 // Calling UpdateDrawProperties must clear this flag, so there can be no 858 // Calling UpdateDrawProperties must clear this flag, so there can be no
852 // early outs before this. 859 // early outs before this.
853 needs_update_draw_properties_ = false; 860 needs_update_draw_properties_ = false;
854 861
855 // For max_texture_size. When the renderer is re-created in 862 // For max_texture_size. When the renderer is re-created in
856 // CreateAndSetRenderer, the needs update draw properties flag is set 863 // CreateAndSetRenderer, the needs update draw properties flag is set
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
1070 } 1077 }
1071 1078
1072 bool LayerTreeImpl::LayerNeedsPushPropertiesForTesting(LayerImpl* layer) { 1079 bool LayerTreeImpl::LayerNeedsPushPropertiesForTesting(LayerImpl* layer) {
1073 return layers_that_should_push_properties_.find(layer) != 1080 return layers_that_should_push_properties_.find(layer) !=
1074 layers_that_should_push_properties_.end(); 1081 layers_that_should_push_properties_.end();
1075 } 1082 }
1076 1083
1077 void LayerTreeImpl::RegisterLayer(LayerImpl* layer) { 1084 void LayerTreeImpl::RegisterLayer(LayerImpl* layer) {
1078 DCHECK(!LayerById(layer->id())); 1085 DCHECK(!LayerById(layer->id()));
1079 layer_id_map_[layer->id()] = layer; 1086 layer_id_map_[layer->id()] = layer;
1080 layer_tree_host_impl_->animation_host()->RegisterElement(
1081 layer->id(),
1082 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING);
1083 } 1087 }
1084 1088
1085 void LayerTreeImpl::UnregisterLayer(LayerImpl* layer) { 1089 void LayerTreeImpl::UnregisterLayer(LayerImpl* layer) {
1086 DCHECK(LayerById(layer->id())); 1090 DCHECK(LayerById(layer->id()));
1087 layer_tree_host_impl_->animation_host()->UnregisterElement(
1088 layer->id(),
1089 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING);
1090 layer_id_map_.erase(layer->id()); 1091 layer_id_map_.erase(layer->id());
1091 } 1092 }
1092 1093
1093 // These manage ownership of the LayerImpl. 1094 // These manage ownership of the LayerImpl.
1094 void LayerTreeImpl::AddLayer(std::unique_ptr<LayerImpl> layer) { 1095 void LayerTreeImpl::AddLayer(std::unique_ptr<LayerImpl> layer) {
1095 DCHECK(std::find(layers_->begin(), layers_->end(), layer) == layers_->end()); 1096 DCHECK(std::find(layers_->begin(), layers_->end(), layer) == layers_->end());
1096 layers_->push_back(std::move(layer)); 1097 layers_->push_back(std::move(layer));
1097 set_needs_update_draw_properties(); 1098 set_needs_update_draw_properties();
1098 } 1099 }
1099 1100
(...skipping 861 matching lines...) Expand 10 before | Expand all | Expand 10 after
1961 1962
1962 std::unique_ptr<PendingPageScaleAnimation> 1963 std::unique_ptr<PendingPageScaleAnimation>
1963 LayerTreeImpl::TakePendingPageScaleAnimation() { 1964 LayerTreeImpl::TakePendingPageScaleAnimation() {
1964 return std::move(pending_page_scale_animation_); 1965 return std::move(pending_page_scale_animation_);
1965 } 1966 }
1966 1967
1967 bool LayerTreeImpl::IsAnimatingFilterProperty(const LayerImpl* layer) const { 1968 bool LayerTreeImpl::IsAnimatingFilterProperty(const LayerImpl* layer) const {
1968 ElementListType list_type = 1969 ElementListType list_type =
1969 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 1970 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
1970 return layer_tree_host_impl_->animation_host()->IsAnimatingFilterProperty( 1971 return layer_tree_host_impl_->animation_host()->IsAnimatingFilterProperty(
1971 layer->id(), list_type); 1972 layer->element_id(), list_type);
1972 } 1973 }
1973 1974
1974 bool LayerTreeImpl::IsAnimatingOpacityProperty(const LayerImpl* layer) const { 1975 bool LayerTreeImpl::IsAnimatingOpacityProperty(const LayerImpl* layer) const {
1975 ElementListType list_type = 1976 ElementListType list_type =
1976 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 1977 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
1977 return layer_tree_host_impl_->animation_host()->IsAnimatingOpacityProperty( 1978 return layer_tree_host_impl_->animation_host()->IsAnimatingOpacityProperty(
1978 layer->id(), list_type); 1979 layer->element_id(), list_type);
1979 } 1980 }
1980 1981
1981 bool LayerTreeImpl::IsAnimatingTransformProperty(const LayerImpl* layer) const { 1982 bool LayerTreeImpl::IsAnimatingTransformProperty(const LayerImpl* layer) const {
1982 ElementListType list_type = 1983 ElementListType list_type =
1983 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 1984 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
1984 return layer_tree_host_impl_->animation_host()->IsAnimatingTransformProperty( 1985 return layer_tree_host_impl_->animation_host()->IsAnimatingTransformProperty(
1985 layer->id(), list_type); 1986 layer->element_id(), list_type);
1986 } 1987 }
1987 1988
1988 bool LayerTreeImpl::HasPotentiallyRunningFilterAnimation( 1989 bool LayerTreeImpl::HasPotentiallyRunningFilterAnimation(
1989 const LayerImpl* layer) const { 1990 const LayerImpl* layer) const {
1990 ElementListType list_type = 1991 ElementListType list_type =
1991 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 1992 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
1992 return layer_tree_host_impl_->animation_host() 1993 return layer_tree_host_impl_->animation_host()
1993 ->HasPotentiallyRunningFilterAnimation(layer->id(), list_type); 1994 ->HasPotentiallyRunningFilterAnimation(layer->element_id(), list_type);
1994 } 1995 }
1995 1996
1996 bool LayerTreeImpl::HasPotentiallyRunningOpacityAnimation( 1997 bool LayerTreeImpl::HasPotentiallyRunningOpacityAnimation(
1997 const LayerImpl* layer) const { 1998 const LayerImpl* layer) const {
1998 ElementListType list_type = 1999 ElementListType list_type =
1999 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 2000 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
2000 return layer_tree_host_impl_->animation_host() 2001 return layer_tree_host_impl_->animation_host()
2001 ->HasPotentiallyRunningOpacityAnimation(layer->id(), list_type); 2002 ->HasPotentiallyRunningOpacityAnimation(layer->element_id(), list_type);
2002 } 2003 }
2003 2004
2004 bool LayerTreeImpl::HasPotentiallyRunningTransformAnimation( 2005 bool LayerTreeImpl::HasPotentiallyRunningTransformAnimation(
2005 const LayerImpl* layer) const { 2006 const LayerImpl* layer) const {
2006 ElementListType list_type = 2007 ElementListType list_type =
2007 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 2008 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
2008 return layer_tree_host_impl_->animation_host() 2009 return layer_tree_host_impl_->animation_host()
2009 ->HasPotentiallyRunningTransformAnimation(layer->id(), list_type); 2010 ->HasPotentiallyRunningTransformAnimation(layer->element_id(), list_type);
2010 } 2011 }
2011 2012
2012 bool LayerTreeImpl::HasAnyAnimationTargetingProperty( 2013 bool LayerTreeImpl::HasAnyAnimationTargetingProperty(
2013 const LayerImpl* layer, 2014 const LayerImpl* layer,
2014 TargetProperty::Type property) const { 2015 TargetProperty::Type property) const {
2015 return layer_tree_host_impl_->animation_host() 2016 return layer_tree_host_impl_->animation_host()
2016 ->HasAnyAnimationTargetingProperty(layer->id(), property); 2017 ->HasAnyAnimationTargetingProperty(layer->element_id(), property);
2017 } 2018 }
2018 2019
2019 bool LayerTreeImpl::AnimationsPreserveAxisAlignment( 2020 bool LayerTreeImpl::AnimationsPreserveAxisAlignment(
2020 const LayerImpl* layer) const { 2021 const LayerImpl* layer) const {
2021 return layer_tree_host_impl_->animation_host() 2022 return layer_tree_host_impl_->animation_host()
2022 ->AnimationsPreserveAxisAlignment(layer->id()); 2023 ->AnimationsPreserveAxisAlignment(layer->element_id());
2023 } 2024 }
2024 2025
2025 bool LayerTreeImpl::HasOnlyTranslationTransforms(const LayerImpl* layer) const { 2026 bool LayerTreeImpl::HasOnlyTranslationTransforms(const LayerImpl* layer) const {
2026 ElementListType list_type = 2027 ElementListType list_type =
2027 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 2028 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
2028 return layer_tree_host_impl_->animation_host()->HasOnlyTranslationTransforms( 2029 return layer_tree_host_impl_->animation_host()->HasOnlyTranslationTransforms(
2029 layer->id(), list_type); 2030 layer->element_id(), list_type);
2030 } 2031 }
2031 2032
2032 bool LayerTreeImpl::MaximumTargetScale(const LayerImpl* layer, 2033 bool LayerTreeImpl::MaximumTargetScale(const LayerImpl* layer,
2033 float* max_scale) const { 2034 float* max_scale) const {
2034 *max_scale = 0.f; 2035 *max_scale = 0.f;
2035 ElementListType list_type = 2036 ElementListType list_type =
2036 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 2037 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
2037 return layer_tree_host_impl_->animation_host()->MaximumTargetScale( 2038 return layer_tree_host_impl_->animation_host()->MaximumTargetScale(
2038 layer->id(), list_type, max_scale); 2039 layer->element_id(), list_type, max_scale);
2039 } 2040 }
2040 2041
2041 bool LayerTreeImpl::AnimationStartScale(const LayerImpl* layer, 2042 bool LayerTreeImpl::AnimationStartScale(const LayerImpl* layer,
2042 float* start_scale) const { 2043 float* start_scale) const {
2043 *start_scale = 0.f; 2044 *start_scale = 0.f;
2044 ElementListType list_type = 2045 ElementListType list_type =
2045 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; 2046 IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING;
2046 return layer_tree_host_impl_->animation_host()->AnimationStartScale( 2047 return layer_tree_host_impl_->animation_host()->AnimationStartScale(
2047 layer->id(), list_type, start_scale); 2048 layer->element_id(), list_type, start_scale);
2048 } 2049 }
2049 2050
2050 bool LayerTreeImpl::HasFilterAnimationThatInflatesBounds( 2051 bool LayerTreeImpl::HasFilterAnimationThatInflatesBounds(
2051 const LayerImpl* layer) const { 2052 const LayerImpl* layer) const {
2052 return layer_tree_host_impl_->animation_host() 2053 return layer_tree_host_impl_->animation_host()
2053 ->HasFilterAnimationThatInflatesBounds(layer->id()); 2054 ->HasFilterAnimationThatInflatesBounds(layer->element_id());
2054 } 2055 }
2055 2056
2056 bool LayerTreeImpl::HasTransformAnimationThatInflatesBounds( 2057 bool LayerTreeImpl::HasTransformAnimationThatInflatesBounds(
2057 const LayerImpl* layer) const { 2058 const LayerImpl* layer) const {
2058 return layer_tree_host_impl_->animation_host() 2059 return layer_tree_host_impl_->animation_host()
2059 ->HasTransformAnimationThatInflatesBounds(layer->id()); 2060 ->HasTransformAnimationThatInflatesBounds(layer->element_id());
2060 } 2061 }
2061 2062
2062 bool LayerTreeImpl::HasAnimationThatInflatesBounds( 2063 bool LayerTreeImpl::HasAnimationThatInflatesBounds(
2063 const LayerImpl* layer) const { 2064 const LayerImpl* layer) const {
2064 return layer_tree_host_impl_->animation_host() 2065 return layer_tree_host_impl_->animation_host()
2065 ->HasAnimationThatInflatesBounds(layer->id()); 2066 ->HasAnimationThatInflatesBounds(layer->element_id());
2066 } 2067 }
2067 2068
2068 bool LayerTreeImpl::FilterAnimationBoundsForBox(const LayerImpl* layer, 2069 bool LayerTreeImpl::FilterAnimationBoundsForBox(const LayerImpl* layer,
2069 const gfx::BoxF& box, 2070 const gfx::BoxF& box,
2070 gfx::BoxF* bounds) const { 2071 gfx::BoxF* bounds) const {
2071 return layer_tree_host_impl_->animation_host()->FilterAnimationBoundsForBox( 2072 return layer_tree_host_impl_->animation_host()->FilterAnimationBoundsForBox(
2072 layer->id(), box, bounds); 2073 layer->element_id(), box, bounds);
2073 } 2074 }
2074 2075
2075 bool LayerTreeImpl::TransformAnimationBoundsForBox(const LayerImpl* layer, 2076 bool LayerTreeImpl::TransformAnimationBoundsForBox(const LayerImpl* layer,
2076 const gfx::BoxF& box, 2077 const gfx::BoxF& box,
2077 gfx::BoxF* bounds) const { 2078 gfx::BoxF* bounds) const {
2078 *bounds = gfx::BoxF(); 2079 *bounds = gfx::BoxF();
2079 return layer_tree_host_impl_->animation_host() 2080 return layer_tree_host_impl_->animation_host()
2080 ->TransformAnimationBoundsForBox(layer->id(), box, bounds); 2081 ->TransformAnimationBoundsForBox(layer->element_id(), box, bounds);
2081 } 2082 }
2082 2083
2083 void LayerTreeImpl::ScrollAnimationAbort(bool needs_completion) { 2084 void LayerTreeImpl::ScrollAnimationAbort(bool needs_completion) {
2084 layer_tree_host_impl_->animation_host()->ScrollAnimationAbort( 2085 layer_tree_host_impl_->animation_host()->ScrollAnimationAbort(
2085 needs_completion); 2086 needs_completion);
2086 } 2087 }
2087 2088
2088 void LayerTreeImpl::ResetAllChangeTracking() { 2089 void LayerTreeImpl::ResetAllChangeTracking() {
2089 layers_that_should_push_properties_.clear(); 2090 layers_that_should_push_properties_.clear();
2090 // Iterate over all layers, including masks and replicas. 2091 // Iterate over all layers, including masks and replicas.
2091 for (auto& layer : *layers_) 2092 for (auto& layer : *layers_)
2092 layer->ResetChangeTracking(); 2093 layer->ResetChangeTracking();
2093 property_trees_.ResetAllChangeTracking(); 2094 property_trees_.ResetAllChangeTracking();
2094 } 2095 }
2095 2096
2096 } // namespace cc 2097 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698