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

Side by Side Diff: Source/core/rendering/RenderBox.cpp

Issue 360833002: Divorce PaintInvalidationState from LayoutState (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: ToT-ed Created 6 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 | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv ed. 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv ed.
7 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. 7 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
(...skipping 1532 matching lines...) Expand 10 before | Expand all | Expand 10 after
1543 } 1543 }
1544 1544
1545 layerRenderer->invalidatePaintRectangle(geometry.destRect()); 1545 layerRenderer->invalidatePaintRectangle(geometry.destRect());
1546 if (geometry.destRect() == rendererRect) 1546 if (geometry.destRect() == rendererRect)
1547 return true; 1547 return true;
1548 } 1548 }
1549 } 1549 }
1550 return false; 1550 return false;
1551 } 1551 }
1552 1552
1553 void RenderBox::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInv alidationContainer) 1553 void RenderBox::invalidateTreeAfterLayout(const InvalidationTreeWalkState& inval idationTreeWalkState)
1554 { 1554 {
1555 // FIXME: Currently only using this logic for RenderBox and its ilk. Ideally , RenderBlockFlows with 1555 // FIXME: Currently only using this logic for RenderBox and its ilk. Ideally , RenderBlockFlows with
1556 // inline children should track a dirty rect in local coordinates for dirty lines instead of invalidating 1556 // inline children should track a dirty rect in local coordinates for dirty lines instead of invalidating
1557 // the world. 1557 // the world.
1558 // FIXME: We should still be recursing through inline's children, as they ca n have boxes, but we don't 1558 // FIXME: We should still be recursing through inline's children, as they ca n have boxes, but we don't
1559 // appear to have tests for this? 1559 // appear to have tests for this?
1560 // FIXME: SVG should probably also go through this unified paint invalidatio n system. 1560 // FIXME: SVG should probably also go through this unified paint invalidatio n system.
1561 ASSERT(!needsLayout()); 1561 ASSERT(!needsLayout());
1562 1562
1563 if (!shouldCheckForPaintInvalidationAfterLayout()) 1563 if (!shouldCheckForPaintInvalidationAfterLayout())
1564 return; 1564 return;
1565 1565
1566 bool establishesNewPaintInvalidationContainer = isPaintInvalidationContainer (); 1566 bool establishesNewPaintInvalidationContainer = isPaintInvalidationContainer ();
1567 const RenderLayerModelObject& newPaintInvalidationContainer = *adjustComposi tedContainerForSpecialAncestors(establishesNewPaintInvalidationContainer ? this : &paintInvalidationContainer); 1567 const RenderLayerModelObject& newPaintInvalidationContainer = *adjustComposi tedContainerForSpecialAncestors(establishesNewPaintInvalidationContainer ? this : &invalidationTreeWalkState.paintInvalidationContainer());
1568 // FIXME: This assert should be re-enabled when we move paint invalidation t o after compositing update. crbug.com/360286 1568 // FIXME: This assert should be re-enabled when we move paint invalidation t o after compositing update. crbug.com/360286
1569 // ASSERT(&newPaintInvalidationContainer == containerForPaintInvalidation()) ; 1569 // ASSERT(&newPaintInvalidationContainer == containerForPaintInvalidation()) ;
1570 1570
1571 const LayoutRect oldPaintInvalidationRect = previousPaintInvalidationRect(); 1571 const LayoutRect oldPaintInvalidationRect = previousPaintInvalidationRect();
1572 const LayoutPoint oldPositionFromPaintInvalidationContainer = previousPositi onFromPaintInvalidationContainer(); 1572 const LayoutPoint oldPositionFromPaintInvalidationContainer = previousPositi onFromPaintInvalidationContainer();
1573 setPreviousPaintInvalidationRect(boundsRectForPaintInvalidation(&newPaintInv alidationContainer)); 1573 setPreviousPaintInvalidationRect(boundsRectForPaintInvalidation(&newPaintInv alidationContainer, &invalidationTreeWalkState));
1574 setPreviousPositionFromPaintInvalidationContainer(RenderLayer::positionFromP aintInvalidationContainer(this, &newPaintInvalidationContainer)); 1574 setPreviousPositionFromPaintInvalidationContainer(RenderLayer::positionFromP aintInvalidationContainer(this, &newPaintInvalidationContainer, &invalidationTre eWalkState));
1575 1575
1576 // If we are set to do a full paint invalidation that means the RenderView w ill be 1576 // If we are set to do a full paint invalidation that means the RenderView w ill be
1577 // issue paint invalidations. We can then skip issuing of paint invalidation s for the child 1577 // issue paint invalidations. We can then skip issuing of paint invalidation s for the child
1578 // renderers as they'll be covered by the RenderView. 1578 // renderers as they'll be covered by the RenderView.
1579 if (view()->doingFullRepaint()) { 1579 if (view()->doingFullRepaint()) {
1580 LayoutState state(*this, isTableRow() ? LayoutSize() : locationOffset()) ; 1580 InvalidationTreeWalkState childTreeWalkState(invalidationTreeWalkState, *this, newPaintInvalidationContainer);
1581 RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); 1581 RenderObject::invalidateTreeAfterLayout(childTreeWalkState);
1582 return; 1582 return;
1583 } 1583 }
1584 1584
1585 if ((onlyNeededPositionedMovementLayout() && compositingState() != PaintsInt oOwnBacking) 1585 if ((onlyNeededPositionedMovementLayout() && compositingState() != PaintsInt oOwnBacking)
1586 || (shouldDoFullPaintInvalidationIfSelfPaintingLayer() 1586 || (shouldDoFullPaintInvalidationIfSelfPaintingLayer()
1587 && hasLayer() 1587 && hasLayer()
1588 && layer()->isSelfPaintingLayer())) { 1588 && layer()->isSelfPaintingLayer())) {
1589 setShouldDoFullPaintInvalidationAfterLayout(true); 1589 setShouldDoFullPaintInvalidationAfterLayout(true);
1590 } 1590 }
1591 1591
1592 if (!invalidatePaintIfNeeded(&newPaintInvalidationContainer, oldPaintInvalid ationRect, oldPositionFromPaintInvalidationContainer)) 1592 if (!invalidatePaintIfNeeded(&newPaintInvalidationContainer, oldPaintInvalid ationRect, oldPositionFromPaintInvalidationContainer))
1593 invalidatePaintForOverflowIfNeeded(); 1593 invalidatePaintForOverflowIfNeeded();
1594 1594
1595 // Issue paint invalidations for any scrollbars if there is a scrollable are a for this renderer. 1595 // Issue paint invalidations for any scrollbars if there is a scrollable are a for this renderer.
1596 if (enclosingLayer()) { 1596 if (enclosingLayer()) {
1597 if (RenderLayerScrollableArea* area = enclosingLayer()->scrollableArea() ) { 1597 if (RenderLayerScrollableArea* area = enclosingLayer()->scrollableArea() ) {
1598 if (area->hasVerticalBarDamage()) 1598 if (area->hasVerticalBarDamage())
1599 invalidatePaintRectangle(area->verticalBarDamage()); 1599 invalidatePaintRectangle(area->verticalBarDamage());
1600 if (area->hasHorizontalBarDamage()) 1600 if (area->hasHorizontalBarDamage())
1601 invalidatePaintRectangle(area->horizontalBarDamage()); 1601 invalidatePaintRectangle(area->horizontalBarDamage());
1602 area->resetScrollbarDamage(); 1602 area->resetScrollbarDamage();
1603 } 1603 }
1604 } 1604 }
1605 1605
1606 // FIXME: LayoutState should be enabled for other paint invalidation contain ers than the RenderView. crbug.com/363834 1606 InvalidationTreeWalkState childTreeWalkState(invalidationTreeWalkState, *thi s, newPaintInvalidationContainer);
1607 if (establishesNewPaintInvalidationContainer && !isRenderView()) { 1607 RenderObject::invalidateTreeAfterLayout(childTreeWalkState);
1608 ForceHorriblySlowRectMapping slowRectMapping(*this);
1609 RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer);
1610 } else {
1611 // FIXME: This concept of a tree walking state for fast lookups should b e generalized away from
1612 // just layout.
1613 // FIXME: Table rows shouldn't be special-cased.
1614 LayoutState state(*this, isTableRow() ? LayoutSize() : locationOffset()) ;
1615 RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer);
1616 }
1617 } 1608 }
1618 1609
1619 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu latedOffset, ContentsClipBehavior contentsClipBehavior) 1610 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu latedOffset, ContentsClipBehavior contentsClipBehavior)
1620 { 1611 {
1621 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == Paint PhaseSelfOutline || paintInfo.phase == PaintPhaseMask) 1612 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == Paint PhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1622 return false; 1613 return false;
1623 1614
1624 bool isControlClip = hasControlClip(); 1615 bool isControlClip = hasControlClip();
1625 bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer(); 1616 bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1626 1617
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1787 if (!logicalHeightLength.isFixed()) { 1778 if (!logicalHeightLength.isFixed()) {
1788 LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritin gMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWid th(); 1779 LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritin gMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWid th();
1789 LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeig ht(ExcludeMarginBorderPadding); 1780 LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeig ht(ExcludeMarginBorderPadding);
1790 return std::min(fillAvailableExtent, fillFallbackExtent); 1781 return std::min(fillAvailableExtent, fillFallbackExtent);
1791 } 1782 }
1792 1783
1793 // Use the content box logical height as specified by the style. 1784 // Use the content box logical height as specified by the style.
1794 return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.val ue()); 1785 return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.val ue());
1795 } 1786 }
1796 1787
1797 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain er, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) co nst 1788 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain er, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, co nst InvalidationTreeWalkState* invalidationTreeWalkState) const
1798 { 1789 {
1799 if (repaintContainer == this) 1790 if (repaintContainer == this)
1800 return; 1791 return;
1801 1792
1802 if (RenderView* v = view()) { 1793 if (invalidationTreeWalkState && invalidationTreeWalkState->canMapToContaine r(repaintContainer)) {
1803 if (v->canMapUsingLayoutStateForContainer(repaintContainer)) { 1794 LayoutSize offset = invalidationTreeWalkState->paintOffset() + locationO ffset();
1804 LayoutState* layoutState = v->layoutState(); 1795 if (style()->hasInFlowPosition() && layer())
1805 LayoutSize offset = layoutState->paintOffset() + locationOffset(); 1796 offset += layer()->offsetForInFlowPosition();
1806 if (style()->hasInFlowPosition() && layer()) 1797 transformState.move(offset);
1807 offset += layer()->offsetForInFlowPosition(); 1798 return;
1808 transformState.move(offset);
1809 return;
1810 }
1811 } 1799 }
1812 1800
1813 bool containerSkipped; 1801 bool containerSkipped;
1814 RenderObject* o = container(repaintContainer, &containerSkipped); 1802 RenderObject* o = container(repaintContainer, &containerSkipped);
1815 if (!o) 1803 if (!o)
1816 return; 1804 return;
1817 1805
1818 bool isFixedPos = style()->position() == FixedPosition; 1806 bool isFixedPos = style()->position() == FixedPosition;
1819 bool hasTransform = hasLayer() && layer()->transform(); 1807 bool hasTransform = hasLayer() && layer()->transform();
1820 // If this box has a transform, it acts as a fixed position container for fi xed descendants, 1808 // If this box has a transform, it acts as a fixed position container for fi xed descendants,
(...skipping 24 matching lines...) Expand all
1845 return; 1833 return;
1846 } 1834 }
1847 1835
1848 mode &= ~ApplyContainerFlip; 1836 mode &= ~ApplyContainerFlip;
1849 1837
1850 o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); 1838 o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1851 } 1839 }
1852 1840
1853 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState & transformState) const 1841 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState & transformState) const
1854 { 1842 {
1855 // We don't expect to be called during layout.
1856 ASSERT(!view() || !view()->layoutStateCachedOffsetsEnabled());
1857
1858 bool isFixedPos = style()->position() == FixedPosition; 1843 bool isFixedPos = style()->position() == FixedPosition;
1859 bool hasTransform = hasLayer() && layer()->transform(); 1844 bool hasTransform = hasLayer() && layer()->transform();
1860 if (hasTransform && !isFixedPos) { 1845 if (hasTransform && !isFixedPos) {
1861 // If this box has a transform, it acts as a fixed position container fo r fixed descendants, 1846 // If this box has a transform, it acts as a fixed position container fo r fixed descendants,
1862 // and may itself also be fixed position. So propagate 'fixed' up only i f this box is fixed position. 1847 // and may itself also be fixed position. So propagate 'fixed' up only i f this box is fixed position.
1863 mode &= ~IsFixed; 1848 mode &= ~IsFixed;
1864 } else if (isFixedPos) 1849 } else if (isFixedPos)
1865 mode |= IsFixed; 1850 mode |= IsFixed;
1866 1851
1867 RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState); 1852 RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1965 { 1950 {
1966 if (inlineBoxWrapper()) { 1951 if (inlineBoxWrapper()) {
1967 if (!documentBeingDestroyed()) 1952 if (!documentBeingDestroyed())
1968 inlineBoxWrapper()->remove(); 1953 inlineBoxWrapper()->remove();
1969 inlineBoxWrapper()->destroy(); 1954 inlineBoxWrapper()->destroy();
1970 ASSERT(m_rareData); 1955 ASSERT(m_rareData);
1971 m_rareData->m_inlineBoxWrapper = 0; 1956 m_rareData->m_inlineBoxWrapper = 0;
1972 } 1957 }
1973 } 1958 }
1974 1959
1975 LayoutRect RenderBox::clippedOverflowRectForPaintInvalidation(const RenderLayerM odelObject* paintInvalidationContainer) const 1960 LayoutRect RenderBox::clippedOverflowRectForPaintInvalidation(const RenderLayerM odelObject* paintInvalidationContainer, const InvalidationTreeWalkState* invalid ationTreeWalkState) const
1976 { 1961 {
1977 if (style()->visibility() != VISIBLE && enclosingLayer()->subtreeIsInvisible ()) 1962 if (style()->visibility() != VISIBLE && enclosingLayer()->subtreeIsInvisible ())
1978 return LayoutRect(); 1963 return LayoutRect();
1979 1964
1980 LayoutRect r = visualOverflowRect(); 1965 LayoutRect r = visualOverflowRect();
1981 mapRectToPaintInvalidationBacking(paintInvalidationContainer, r); 1966 mapRectToPaintInvalidationBacking(paintInvalidationContainer, r, invalidatio nTreeWalkState);
1982 return r; 1967 return r;
1983 } 1968 }
1984 1969
1985 void RenderBox::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const 1970 void RenderBox::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed, const InvalidationTree WalkState* invalidationTreeWalkState) const
1986 { 1971 {
1987 // The rect we compute at each step is shifted by our x/y offset in the pare nt container's coordinate space. 1972 // The rect we compute at each step is shifted by our x/y offset in the pare nt container's coordinate space.
1988 // Only when we cross a writing mode boundary will we have to possibly flipF orWritingMode (to convert into a more appropriate 1973 // Only when we cross a writing mode boundary will we have to possibly flipF orWritingMode (to convert into a more appropriate
1989 // offset corner for the enclosing container). This allows for a fully RL o r BT document to repaint 1974 // offset corner for the enclosing container). This allows for a fully RL o r BT document to repaint
1990 // properly even during layout, since the rect remains flipped all the way u ntil the end. 1975 // properly even during layout, since the rect remains flipped all the way u ntil the end.
1991 // 1976 //
1992 // RenderView::computeRectForRepaint then converts the rect to physical coor dinates. We also convert to 1977 // RenderView::computeRectForRepaint then converts the rect to physical coor dinates. We also convert to
1993 // physical when we hit a paintInvalidationContainer boundary. Therefore the final rect returned is always in the 1978 // physical when we hit a paintInvalidationContainer boundary. Therefore the final rect returned is always in the
1994 // physical coordinate space of the paintInvalidationContainer. 1979 // physical coordinate space of the paintInvalidationContainer.
1995 RenderStyle* styleToUse = style(); 1980 RenderStyle* styleToUse = style();
1996 if (RenderView* v = view()) {
1997 // LayoutState is only valid for root-relative, non-fixed position repai nting
1998 if (v->canMapUsingLayoutStateForContainer(paintInvalidationContainer) && styleToUse->position() != FixedPosition) {
1999 LayoutState* layoutState = v->layoutState();
2000 1981
2001 if (layer() && layer()->transform()) 1982 if (invalidationTreeWalkState && invalidationTreeWalkState->canMapToContaine r(paintInvalidationContainer) && styleToUse->position() != FixedPosition) {
2002 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect)); 1983 if (layer() && layer()->transform())
1984 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2003 1985
2004 // We can't trust the bits on RenderObject, because this might be ca lled while re-resolving style. 1986 // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
2005 if (styleToUse->hasInFlowPosition() && layer()) 1987 if (styleToUse->hasInFlowPosition() && layer())
2006 rect.move(layer()->offsetForInFlowPosition()); 1988 rect.move(layer()->offsetForInFlowPosition());
2007 1989
2008 rect.moveBy(location()); 1990 rect.moveBy(location());
2009 rect.move(layoutState->paintOffset()); 1991 rect.move(invalidationTreeWalkState->paintOffset());
2010 if (layoutState->isClipped()) 1992 if (invalidationTreeWalkState->isClipped())
2011 rect.intersect(layoutState->clipRect()); 1993 rect.intersect(invalidationTreeWalkState->clipRect());
2012 return; 1994 return;
2013 }
2014 } 1995 }
2015 1996
2016 if (hasReflection()) 1997 if (hasReflection())
2017 rect.unite(reflectedRect(rect)); 1998 rect.unite(reflectedRect(rect));
2018 1999
2019 if (paintInvalidationContainer == this) { 2000 if (paintInvalidationContainer == this) {
2020 if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode()) 2001 if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode())
2021 flipForWritingMode(rect); 2002 flipForWritingMode(rect);
2022 return; 2003 return;
2023 } 2004 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
2072 return; 2053 return;
2073 } 2054 }
2074 2055
2075 if (containerSkipped) { 2056 if (containerSkipped) {
2076 // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates. 2057 // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates.
2077 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAnces torContainer(o); 2058 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAnces torContainer(o);
2078 rect.move(-containerOffset); 2059 rect.move(-containerOffset);
2079 return; 2060 return;
2080 } 2061 }
2081 2062
2082 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed ); 2063 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed , invalidationTreeWalkState);
2083 } 2064 }
2084 2065
2085 void RenderBox::invalidatePaintForOverhangingFloats(bool) 2066 void RenderBox::invalidatePaintForOverhangingFloats(bool)
2086 { 2067 {
2087 } 2068 }
2088 2069
2089 void RenderBox::updateLogicalWidth() 2070 void RenderBox::updateLogicalWidth()
2090 { 2071 {
2091 LogicalExtentComputedValues computedValues; 2072 LogicalExtentComputedValues computedValues;
2092 computeLogicalWidth(computedValues); 2073 computeLogicalWidth(computedValues);
(...skipping 2584 matching lines...) Expand 10 before | Expand all | Expand 10 after
4677 return 0; 4658 return 0;
4678 4659
4679 if (!layoutState && !flowThreadContainingBlock()) 4660 if (!layoutState && !flowThreadContainingBlock())
4680 return 0; 4661 return 0;
4681 4662
4682 RenderBlock* containerBlock = containingBlock(); 4663 RenderBlock* containerBlock = containingBlock();
4683 return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop(); 4664 return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
4684 } 4665 }
4685 4666
4686 } // namespace WebCore 4667 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698