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

Side by Side Diff: Source/core/paint/DeprecatedPaintLayer.cpp

Issue 1032823003: Refactor HitTestResult to store the HitTestRequest (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Updated as per review comments Created 5 years, 8 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
« no previous file with comments | « Source/core/paint/DeprecatedPaintLayer.h ('k') | Source/core/testing/Internals.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3 * 3 *
4 * Portions are Copyright (C) 1998 Netscape Communications Corporation. 4 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
5 * 5 *
6 * Other contributors: 6 * Other contributors:
7 * Robert O'Callahan <roc+@cs.cmu.edu> 7 * Robert O'Callahan <roc+@cs.cmu.edu>
8 * David Baron <dbaron@fas.harvard.edu> 8 * David Baron <dbaron@fas.harvard.edu>
9 * Christian Biesinger <cbiesinger@web.de> 9 * Christian Biesinger <cbiesinger@web.de>
10 * Randall Jesup <rjesup@wgate.com> 10 * Randall Jesup <rjesup@wgate.com>
(...skipping 1642 matching lines...) Expand 10 before | Expand all | Expand 10 after
1653 1653
1654 static inline LayoutRect frameVisibleRect(LayoutObject* renderer) 1654 static inline LayoutRect frameVisibleRect(LayoutObject* renderer)
1655 { 1655 {
1656 FrameView* frameView = renderer->document().view(); 1656 FrameView* frameView = renderer->document().view();
1657 if (!frameView) 1657 if (!frameView)
1658 return LayoutRect(); 1658 return LayoutRect();
1659 1659
1660 return LayoutRect(frameView->visibleContentRect()); 1660 return LayoutRect(frameView->visibleContentRect());
1661 } 1661 }
1662 1662
1663 bool DeprecatedPaintLayer::hitTest(const HitTestRequest& request, HitTestResult& result) 1663 bool DeprecatedPaintLayer::hitTest(HitTestResult& result)
1664 { 1664 {
1665 return hitTest(request, result.hitTestLocation(), result); 1665 return hitTest(result.hitTestRequest(), result.hitTestLocation(), result);
1666 } 1666 }
1667 1667
1668 bool DeprecatedPaintLayer::hitTest(const HitTestRequest& request, const HitTestL ocation& hitTestLocation, HitTestResult& result) 1668 bool DeprecatedPaintLayer::hitTest(const HitTestRequest& request, const HitTestL ocation& hitTestLocation, HitTestResult& result)
1669 { 1669 {
1670 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 1670 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
1671 1671
1672 // LayoutView should make sure to update layout before entering hit testing 1672 // LayoutView should make sure to update layout before entering hit testing
1673 ASSERT(!layoutObject()->frame()->view()->layoutPending()); 1673 ASSERT(!layoutObject()->frame()->view()->layoutPending());
1674 ASSERT(!layoutObject()->document().layoutView()->needsLayout()); 1674 ASSERT(!layoutObject()->document().layoutView()->needsLayout());
1675 1675
1676 // Start with frameVisibleRect to ensure we include the scrollbars. 1676 // Start with frameVisibleRect to ensure we include the scrollbars.
1677 LayoutRect hitTestArea = frameVisibleRect(layoutObject()); 1677 LayoutRect hitTestArea = frameVisibleRect(layoutObject());
1678 if (request.ignoreClipping()) 1678 if (request.ignoreClipping())
1679 hitTestArea.unite(LayoutRect(layoutObject()->view()->documentRect())); 1679 hitTestArea.unite(LayoutRect(layoutObject()->view()->documentRect()));
1680 1680
1681 DeprecatedPaintLayer* insideLayer = hitTestLayer(this, 0, request, result, h itTestArea, hitTestLocation, false); 1681 DeprecatedPaintLayer* insideLayer = hitTestLayer(this, 0, result, hitTestAre a, hitTestLocation, false);
1682 if (!insideLayer) { 1682 if (!insideLayer) {
1683 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, 1683 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
1684 // return ourselves. We do this so mouse events continue getting deliver ed after a drag has 1684 // return ourselves. We do this so mouse events continue getting deliver ed after a drag has
1685 // exited the WebView, and so hit testing over a scrollbar hits the cont ent document. 1685 // exited the WebView, and so hit testing over a scrollbar hits the cont ent document.
1686 // In addtion, it is possible for the mouse to stay in the document but there is no element. 1686 // In addtion, it is possible for the mouse to stay in the document but there is no element.
1687 // At that time, the events of the mouse should be fired. 1687 // At that time, the events of the mouse should be fired.
1688 LayoutPoint hitPoint = hitTestLocation.point(); 1688 LayoutPoint hitPoint = hitTestLocation.point();
1689 if (!request.isChildFrameHitTest() && ((request.active() || request.rele ase()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y()))) && isRootLayer()) { 1689 if (!request.isChildFrameHitTest() && ((request.active() || request.rele ase()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y()))) && isRootLayer()) {
1690 layoutObject()->updateHitTestResult(result, toLayoutView(layoutObjec t())->flipForWritingMode(hitTestLocation.point())); 1690 layoutObject()->updateHitTestResult(result, toLayoutView(layoutObjec t())->flipForWritingMode(hitTestLocation.point()));
1691 insideLayer = this; 1691 insideLayer = this;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1792 } 1792 }
1793 1793
1794 // hitTestLocation and hitTestRect are relative to rootLayer. 1794 // hitTestLocation and hitTestRect are relative to rootLayer.
1795 // A 'flattening' layer is one preserves3D() == false. 1795 // A 'flattening' layer is one preserves3D() == false.
1796 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer. 1796 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
1797 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the c ontaining flattening layer. 1797 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the c ontaining flattening layer.
1798 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer. 1798 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
1799 // 1799 //
1800 // If zOffset is non-null (which indicates that the caller wants z offset inform ation), 1800 // If zOffset is non-null (which indicates that the caller wants z offset inform ation),
1801 // *zOffset on return is the z offset of the hit point relative to the containi ng flattening layer. 1801 // *zOffset on return is the z offset of the hit point relative to the containi ng flattening layer.
1802 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestLayer(DeprecatedPaintLayer* r ootLayer, DeprecatedPaintLayer* containerLayer, const HitTestRequest& request, H itTestResult& result, 1802 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestLayer(DeprecatedPaintLayer* r ootLayer, DeprecatedPaintLayer* containerLayer, HitTestResult& result,
1803 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform, 1803 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform,
1804 const HitTestingTransformState* transformState, double* zOffset) 1804 const HitTestingTransformState* transformState, double* zOffset)
1805 { 1805 {
1806 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) 1806 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
1807 return 0; 1807 return 0;
1808 1808
1809 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. 1809 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
1810 1810
1811 // Apply a transform if we have one. 1811 // Apply a transform if we have one.
1812 if (transform() && !appliedTransform) { 1812 if (transform() && !appliedTransform) {
1813 if (enclosingPaginationLayer()) 1813 if (enclosingPaginationLayer())
1814 return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset); 1814 return hitTestTransformedLayerInFragments(rootLayer, containerLayer, result, hitTestRect, hitTestLocation, transformState, zOffset);
1815 1815
1816 // Make sure the parent's clip rects have been calculated. 1816 // Make sure the parent's clip rects have been calculated.
1817 if (parent()) { 1817 if (parent()) {
1818 ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(ro otLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize)); 1818 ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(ro otLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize));
1819 // Go ahead and test the enclosing clip now. 1819 // Go ahead and test the enclosing clip now.
1820 if (!clipRect.intersects(hitTestLocation)) 1820 if (!clipRect.intersects(hitTestLocation))
1821 return 0; 1821 return 0;
1822 } 1822 }
1823 1823
1824 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, reques t, result, hitTestRect, hitTestLocation, transformState, zOffset); 1824 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, result , hitTestRect, hitTestLocation, transformState, zOffset);
1825 } 1825 }
1826 1826
1827 // Ensure our lists and 3d status are up-to-date. 1827 // Ensure our lists and 3d status are up-to-date.
1828 m_stackingNode->updateLayerListsIfNeeded(); 1828 m_stackingNode->updateLayerListsIfNeeded();
1829 update3DTransformedDescendantStatus(); 1829 update3DTransformedDescendantStatus();
1830 1830
1831 RefPtr<HitTestingTransformState> localTransformState; 1831 RefPtr<HitTestingTransformState> localTransformState;
1832 if (appliedTransform) { 1832 if (appliedTransform) {
1833 // We computed the correct state in the caller (above code), so just ref erence it. 1833 // We computed the correct state in the caller (above code), so just ref erence it.
1834 ASSERT(transformState); 1834 ASSERT(transformState);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1869 } else if (zOffset) { 1869 } else if (zOffset) {
1870 zOffsetForDescendantsPtr = 0; 1870 zOffsetForDescendantsPtr = 0;
1871 // Container needs us to give back a z offset for the hit layer. 1871 // Container needs us to give back a z offset for the hit layer.
1872 zOffsetForContentsPtr = zOffset; 1872 zOffsetForContentsPtr = zOffset;
1873 } 1873 }
1874 1874
1875 // This variable tracks which layer the mouse ends up being inside. 1875 // This variable tracks which layer the mouse ends up being inside.
1876 DeprecatedPaintLayer* candidateLayer = 0; 1876 DeprecatedPaintLayer* candidateLayer = 0;
1877 1877
1878 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. 1878 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
1879 DeprecatedPaintLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, roo tLayer, request, result, hitTestRect, hitTestLocation, 1879 DeprecatedPaintLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, roo tLayer, result, hitTestRect, hitTestLocation,
1880 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene dTransformState.get(), depthSortDescendants); 1880 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene dTransformState.get(), depthSortDescendants);
1881 if (hitLayer) { 1881 if (hitLayer) {
1882 if (!depthSortDescendants) 1882 if (!depthSortDescendants)
1883 return hitLayer; 1883 return hitLayer;
1884 candidateLayer = hitLayer; 1884 candidateLayer = hitLayer;
1885 } 1885 }
1886 1886
1887 // Now check our overflow objects. 1887 // Now check our overflow objects.
1888 hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, h itTestRect, hitTestLocation, 1888 hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, result, hitTestRec t, hitTestLocation,
1889 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene dTransformState.get(), depthSortDescendants); 1889 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene dTransformState.get(), depthSortDescendants);
1890 if (hitLayer) { 1890 if (hitLayer) {
1891 if (!depthSortDescendants) 1891 if (!depthSortDescendants)
1892 return hitLayer; 1892 return hitLayer;
1893 candidateLayer = hitLayer; 1893 candidateLayer = hitLayer;
1894 } 1894 }
1895 1895
1896 // Collect the fragments. This will compute the clip rectangles for each lay er fragment. 1896 // Collect the fragments. This will compute the clip rectangles for each lay er fragment.
1897 DeprecatedPaintLayerFragments layerFragments; 1897 DeprecatedPaintLayerFragments layerFragments;
1898 if (appliedTransform) 1898 if (appliedTransform)
1899 appendSingleFragmentIgnoringPagination(layerFragments, rootLayer, hitTes tRect, RootRelativeClipRects, IncludeOverlayScrollbarSize); 1899 appendSingleFragmentIgnoringPagination(layerFragments, rootLayer, hitTes tRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
1900 else 1900 else
1901 collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeCli pRects, IncludeOverlayScrollbarSize); 1901 collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeCli pRects, IncludeOverlayScrollbarSize);
1902 1902
1903 if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFra gments, hitTestLocation)) { 1903 if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFra gments, hitTestLocation)) {
1904 layoutObject()->updateHitTestResult(result, hitTestLocation.point()); 1904 layoutObject()->updateHitTestResult(result, hitTestLocation.point());
1905 return this; 1905 return this;
1906 } 1906 }
1907 1907
1908 // Next we want to see if the mouse pos is inside the child LayoutObjects of the layer. Check 1908 // Next we want to see if the mouse pos is inside the child LayoutObjects of the layer. Check
1909 // every fragment in reverse order. 1909 // every fragment in reverse order.
1910 if (isSelfPaintingLayer()) { 1910 if (isSelfPaintingLayer()) {
1911 // Hit test with a temporary HitTestResult, because we only want to comm it to 'result' if we know we're frontmost. 1911 // Hit test with a temporary HitTestResult, because we only want to comm it to 'result' if we know we're frontmost.
1912 HitTestResult tempResult(result.hitTestLocation()); 1912 HitTestResult tempResult(result.hitTestRequest(), result.hitTestLocation ());
1913 bool insideFragmentForegroundRect = false; 1913 bool insideFragmentForegroundRect = false;
1914 if (hitTestContentsForFragments(layerFragments, request, tempResult, hit TestLocation, HitTestDescendants, insideFragmentForegroundRect) 1914 if (hitTestContentsForFragments(layerFragments, tempResult, hitTestLocat ion, HitTestDescendants, insideFragmentForegroundRect)
1915 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra nsformState.get())) { 1915 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra nsformState.get())) {
1916 if (request.listBased()) 1916 if (result.hitTestRequest().listBased())
1917 result.append(tempResult, request); 1917 result.append(tempResult);
1918 else 1918 else
1919 result = tempResult; 1919 result = tempResult;
1920 if (!depthSortDescendants) 1920 if (!depthSortDescendants)
1921 return this; 1921 return this;
1922 // Foreground can depth-sort with descendant layers, so keep this as a candidate. 1922 // Foreground can depth-sort with descendant layers, so keep this as a candidate.
1923 candidateLayer = this; 1923 candidateLayer = this;
1924 } else if (insideFragmentForegroundRect && request.listBased()) { 1924 } else if (insideFragmentForegroundRect && result.hitTestRequest().listB ased()) {
1925 result.append(tempResult, request); 1925 result.append(tempResult);
1926 } 1926 }
1927 } 1927 }
1928 1928
1929 // Now check our negative z-index children. 1929 // Now check our negative z-index children.
1930 hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, resul t, hitTestRect, hitTestLocation, 1930 hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, result, hitTes tRect, hitTestLocation,
1931 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene dTransformState.get(), depthSortDescendants); 1931 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene dTransformState.get(), depthSortDescendants);
1932 if (hitLayer) { 1932 if (hitLayer) {
1933 if (!depthSortDescendants) 1933 if (!depthSortDescendants)
1934 return hitLayer; 1934 return hitLayer;
1935 candidateLayer = hitLayer; 1935 candidateLayer = hitLayer;
1936 } 1936 }
1937 1937
1938 // If we found a layer, return. Child layers, and foreground always render i n front of background. 1938 // If we found a layer, return. Child layers, and foreground always render i n front of background.
1939 if (candidateLayer) 1939 if (candidateLayer)
1940 return candidateLayer; 1940 return candidateLayer;
1941 1941
1942 if (isSelfPaintingLayer()) { 1942 if (isSelfPaintingLayer()) {
1943 HitTestResult tempResult(result.hitTestLocation()); 1943 HitTestResult tempResult(result.hitTestRequest(), result.hitTestLocation ());
1944 bool insideFragmentBackgroundRect = false; 1944 bool insideFragmentBackgroundRect = false;
1945 if (hitTestContentsForFragments(layerFragments, request, tempResult, hit TestLocation, HitTestSelf, insideFragmentBackgroundRect) 1945 if (hitTestContentsForFragments(layerFragments, tempResult, hitTestLocat ion, HitTestSelf, insideFragmentBackgroundRect)
1946 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra nsformState.get())) { 1946 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra nsformState.get())) {
1947 if (result.isRectBasedTest()) 1947 if (result.isRectBasedTest())
1948 result.append(tempResult, request); 1948 result.append(tempResult);
1949 else 1949 else
1950 result = tempResult; 1950 result = tempResult;
1951 return this; 1951 return this;
1952 } 1952 }
1953 if (insideFragmentBackgroundRect && request.listBased()) 1953 if (insideFragmentBackgroundRect && result.hitTestRequest().listBased())
1954 result.append(tempResult, request); 1954 result.append(tempResult);
1955 } 1955 }
1956 1956
1957 return 0; 1957 return 0;
1958 } 1958 }
1959 1959
1960 bool DeprecatedPaintLayer::hitTestContentsForFragments(const DeprecatedPaintLaye rFragments& layerFragments, const HitTestRequest& request, HitTestResult& result , 1960 bool DeprecatedPaintLayer::hitTestContentsForFragments(const DeprecatedPaintLaye rFragments& layerFragments, HitTestResult& result,
1961 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& i nsideClipRect) const 1961 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& i nsideClipRect) const
1962 { 1962 {
1963 if (layerFragments.isEmpty()) 1963 if (layerFragments.isEmpty())
1964 return false; 1964 return false;
1965 1965
1966 for (int i = layerFragments.size() - 1; i >= 0; --i) { 1966 for (int i = layerFragments.size() - 1; i >= 0; --i) {
1967 const DeprecatedPaintLayerFragment& fragment = layerFragments.at(i); 1967 const DeprecatedPaintLayerFragment& fragment = layerFragments.at(i);
1968 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects (hitTestLocation)) 1968 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects (hitTestLocation))
1969 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect. intersects(hitTestLocation))) 1969 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect. intersects(hitTestLocation)))
1970 continue; 1970 continue;
1971 insideClipRect = true; 1971 insideClipRect = true;
1972 if (hitTestContents(request, result, fragment.layerBounds, hitTestLocati on, hitTestFilter)) 1972 if (hitTestContents(result, fragment.layerBounds, hitTestLocation, hitTe stFilter))
1973 return true; 1973 return true;
1974 } 1974 }
1975 1975
1976 return false; 1976 return false;
1977 } 1977 }
1978 1978
1979 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestTransformedLayerInFragments(D eprecatedPaintLayer* rootLayer, DeprecatedPaintLayer* containerLayer, const HitT estRequest& request, HitTestResult& result, 1979 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestTransformedLayerInFragments(D eprecatedPaintLayer* rootLayer, DeprecatedPaintLayer* containerLayer, HitTestRes ult& result,
1980 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset) 1980 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
1981 { 1981 {
1982 DeprecatedPaintLayerFragments enclosingPaginationFragments; 1982 DeprecatedPaintLayerFragments enclosingPaginationFragments;
1983 LayoutPoint offsetOfPaginationLayerFromRoot; 1983 LayoutPoint offsetOfPaginationLayerFromRoot;
1984 // FIXME: We're missing a sub-pixel offset here crbug.com/348728 1984 // FIXME: We're missing a sub-pixel offset here crbug.com/348728
1985 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPagination Layer(), HitTestingTransparencyClipBox, DeprecatedPaintLayer::RootOfTransparency ClipBox, LayoutSize()); 1985 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPagination Layer(), HitTestingTransparencyClipBox, DeprecatedPaintLayer::RootOfTransparency ClipBox, LayoutSize());
1986 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, r ootLayer, hitTestRect, 1986 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, r ootLayer, hitTestRect,
1987 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent); 1987 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent);
1988 1988
1989 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) { 1989 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
1990 const DeprecatedPaintLayerFragment& fragment = enclosingPaginationFragme nts.at(i); 1990 const DeprecatedPaintLayerFragment& fragment = enclosingPaginationFragme nts.at(i);
1991 1991
1992 // Apply the page/column clip for this fragment, as well as any clips es tablished by layers in between us and 1992 // Apply the page/column clip for this fragment, as well as any clips es tablished by layers in between us and
1993 // the enclosing pagination layer. 1993 // the enclosing pagination layer.
1994 LayoutRect clipRect = fragment.backgroundRect.rect(); 1994 LayoutRect clipRect = fragment.backgroundRect.rect();
1995 1995
1996 // Now compute the clips within a given fragment 1996 // Now compute the clips within a given fragment
1997 if (parent() != enclosingPaginationLayer()) { 1997 if (parent() != enclosingPaginationLayer()) {
1998 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOf PaginationLayerFromRoot); 1998 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOf PaginationLayerFromRoot);
1999 LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsCo ntext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbar Size)).rect(); 1999 LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsCo ntext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbar Size)).rect();
2000 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPagination LayerFromRoot); 2000 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPagination LayerFromRoot);
2001 clipRect.intersect(parentClipRect); 2001 clipRect.intersect(parentClipRect);
2002 } 2002 }
2003 2003
2004 if (!hitTestLocation.intersects(clipRect)) 2004 if (!hitTestLocation.intersects(clipRect))
2005 continue; 2005 continue;
2006 2006
2007 DeprecatedPaintLayer* hitLayer = hitTestLayerByApplyingTransform(rootLay er, containerLayer, request, result, hitTestRect, hitTestLocation, 2007 DeprecatedPaintLayer* hitLayer = hitTestLayerByApplyingTransform(rootLay er, containerLayer, result, hitTestRect, hitTestLocation,
2008 transformState, zOffset, fragment.paginationOffset); 2008 transformState, zOffset, fragment.paginationOffset);
2009 if (hitLayer) 2009 if (hitLayer)
2010 return hitLayer; 2010 return hitLayer;
2011 } 2011 }
2012 2012
2013 return 0; 2013 return 0;
2014 } 2014 }
2015 2015
2016 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestLayerByApplyingTransform(Depr ecatedPaintLayer* rootLayer, DeprecatedPaintLayer* containerLayer, const HitTest Request& request, HitTestResult& result, 2016 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestLayerByApplyingTransform(Depr ecatedPaintLayer* rootLayer, DeprecatedPaintLayer* containerLayer, HitTestResult & result,
2017 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset, 2017 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
2018 const LayoutPoint& translationOffset) 2018 const LayoutPoint& translationOffset)
2019 { 2019 {
2020 // Create a transform state to accumulate this transform. 2020 // Create a transform state to accumulate this transform.
2021 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformSta te(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, tran slationOffset); 2021 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformSta te(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, tran slationOffset);
2022 2022
2023 // If the transform can't be inverted, then don't hit test this layer at all . 2023 // If the transform can't be inverted, then don't hit test this layer at all .
2024 if (!newTransformState->m_accumulatedTransform.isInvertible()) 2024 if (!newTransformState->m_accumulatedTransform.isInvertible())
2025 return 0; 2025 return 0;
2026 2026
2027 // Compute the point and the hit test rect in the coords of this layer by us ing the values 2027 // Compute the point and the hit test rect in the coords of this layer by us ing the values
2028 // from the transformState, which store the point and quad in the coords of the last flattened 2028 // from the transformState, which store the point and quad in the coords of the last flattened
2029 // layer, and the accumulated transform which lets up map through preserve-3 d layers. 2029 // layer, and the accumulated transform which lets up map through preserve-3 d layers.
2030 // 2030 //
2031 // We can't just map hitTestLocation and hitTestRect because they may have b een flattened (losing z) 2031 // We can't just map hitTestLocation and hitTestRect because they may have b een flattened (losing z)
2032 // by our container. 2032 // by our container.
2033 FloatPoint localPoint = newTransformState->mappedPoint(); 2033 FloatPoint localPoint = newTransformState->mappedPoint();
2034 FloatQuad localPointQuad = newTransformState->mappedQuad(); 2034 FloatQuad localPointQuad = newTransformState->mappedQuad();
2035 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea(); 2035 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
2036 HitTestLocation newHitTestLocation; 2036 HitTestLocation newHitTestLocation;
2037 if (hitTestLocation.isRectBasedTest()) 2037 if (hitTestLocation.isRectBasedTest())
2038 newHitTestLocation = HitTestLocation(localPoint, localPointQuad); 2038 newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
2039 else 2039 else
2040 newHitTestLocation = HitTestLocation(localPoint); 2040 newHitTestLocation = HitTestLocation(localPoint);
2041 2041
2042 // Now do a hit test with the root layer shifted to be us. 2042 // Now do a hit test with the root layer shifted to be us.
2043 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset); 2043 return hitTestLayer(this, containerLayer, result, localHitTestRect, newHitTe stLocation, true, newTransformState.get(), zOffset);
2044 } 2044 }
2045 2045
2046 bool DeprecatedPaintLayer::hitTestContents(const HitTestRequest& request, HitTes tResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLo cation, HitTestFilter hitTestFilter) const 2046 bool DeprecatedPaintLayer::hitTestContents(HitTestResult& result, const LayoutRe ct& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFi lter) const
2047 { 2047 {
2048 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); 2048 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
2049 2049
2050 if (!layoutObject()->hitTest(request, result, hitTestLocation, toLayoutPoint (layerBounds.location() - layoutBoxLocation()), hitTestFilter)) { 2050 if (!layoutObject()->hitTest(result, hitTestLocation, toLayoutPoint(layerBou nds.location() - layoutBoxLocation()), hitTestFilter)) {
2051 // It's wrong to set innerNode, but then claim that you didn't hit anyth ing, unless it is 2051 // It's wrong to set innerNode, but then claim that you didn't hit anyth ing, unless it is
2052 // a rect-based test. 2052 // a rect-based test.
2053 ASSERT(!result.innerNode() || (request.listBased() && result.listBasedTe stResult().size())); 2053 ASSERT(!result.innerNode() || (result.hitTestRequest().listBased() && re sult.listBasedTestResult().size()));
2054 return false; 2054 return false;
2055 } 2055 }
2056 2056
2057 if (!result.innerNode() || !result.innerNonSharedNode()) { 2057 if (!result.innerNode() || !result.innerNonSharedNode()) {
2058 // We hit something anonymous, and we didn't find a DOM node ancestor in this layer. 2058 // We hit something anonymous, and we didn't find a DOM node ancestor in this layer.
2059 2059
2060 if (layoutObject()->isLayoutFlowThread()) { 2060 if (layoutObject()->isLayoutFlowThread()) {
2061 // For a flow thread it's safe to just say that we didn't hit anythi ng. That means that 2061 // For a flow thread it's safe to just say that we didn't hit anythi ng. That means that
2062 // we'll continue as normally, and eventually hit a column set sibli ng instead. Column 2062 // we'll continue as normally, and eventually hit a column set sibli ng instead. Column
2063 // sets are also anonymous, but, unlike flow threads, they don't est ablish layers, so 2063 // sets are also anonymous, but, unlike flow threads, they don't est ablish layers, so
2064 // we'll fall back and hit the multicol container parent (which shou ld have a DOM node). 2064 // we'll fall back and hit the multicol container parent (which shou ld have a DOM node).
2065 return false; 2065 return false;
2066 } 2066 }
2067 2067
2068 Node* e = enclosingElement(); 2068 Node* e = enclosingElement();
2069 if (!result.innerNode()) 2069 if (!result.innerNode())
2070 result.setInnerNode(e); 2070 result.setInnerNode(e);
2071 if (!result.innerNonSharedNode()) 2071 if (!result.innerNonSharedNode())
2072 result.setInnerNonSharedNode(e); 2072 result.setInnerNonSharedNode(e);
2073 // FIXME: missing call to result.setLocalPoint(). What we would really w ant to do here is to 2073 // FIXME: missing call to result.setLocalPoint(). What we would really w ant to do here is to
2074 // return and look for the nearest non-anonymous ancestor, and ignore au nts and uncles on 2074 // return and look for the nearest non-anonymous ancestor, and ignore au nts and uncles on
2075 // our way. It's bad to look for it manually like we do here, and give u p on setting a local 2075 // our way. It's bad to look for it manually like we do here, and give u p on setting a local
2076 // point in the result, because that has bad implications for text selec tion and 2076 // point in the result, because that has bad implications for text selec tion and
2077 // caretRangeFromPoint(). See crbug.com/461791 2077 // caretRangeFromPoint(). See crbug.com/461791
2078 } 2078 }
2079 return true; 2079 return true;
2080 } 2080 }
2081 2081
2082 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestChildren(ChildrenIteration ch ildrentoVisit, DeprecatedPaintLayer* rootLayer, 2082 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestChildren(ChildrenIteration ch ildrentoVisit, DeprecatedPaintLayer* rootLayer,
2083 const HitTestRequest& request, HitTestResult& result, 2083 HitTestResult& result,
2084 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, 2084 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
2085 const HitTestingTransformState* transformState, 2085 const HitTestingTransformState* transformState,
2086 double* zOffsetForDescendants, double* zOffset, 2086 double* zOffsetForDescendants, double* zOffset,
2087 const HitTestingTransformState* unflattenedTransformState, 2087 const HitTestingTransformState* unflattenedTransformState,
2088 bool depthSortDescendants) 2088 bool depthSortDescendants)
2089 { 2089 {
2090 if (!hasSelfPaintingLayerDescendant()) 2090 if (!hasSelfPaintingLayerDescendant())
2091 return 0; 2091 return 0;
2092 2092
2093 DeprecatedPaintLayer* resultLayer = 0; 2093 DeprecatedPaintLayer* resultLayer = 0;
2094 DeprecatedPaintLayerStackingNodeReverseIterator iterator(*m_stackingNode, ch ildrentoVisit); 2094 DeprecatedPaintLayerStackingNodeReverseIterator iterator(*m_stackingNode, ch ildrentoVisit);
2095 while (DeprecatedPaintLayerStackingNode* child = iterator.next()) { 2095 while (DeprecatedPaintLayerStackingNode* child = iterator.next()) {
2096 DeprecatedPaintLayer* childLayer = child->layer(); 2096 DeprecatedPaintLayer* childLayer = child->layer();
2097 DeprecatedPaintLayer* hitLayer = 0; 2097 DeprecatedPaintLayer* hitLayer = 0;
2098 HitTestResult tempResult(result.hitTestLocation()); 2098 HitTestResult tempResult(result.hitTestRequest(), result.hitTestLocation ());
2099 if (childLayer->isPaginated()) 2099 if (childLayer->isPaginated())
2100 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request , tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendant s); 2100 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, tempRes ult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants);
2101 else 2101 else
2102 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempRe sult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants ); 2102 hitLayer = childLayer->hitTestLayer(rootLayer, this, tempResult, hit TestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
2103 2103
2104 // If it is a list-based test, we can safely append the temporary result since it might had hit 2104 // If it is a list-based test, we can safely append the temporary result since it might had hit
2105 // nodes but not necesserily had hitLayer set. 2105 // nodes but not necesserily had hitLayer set.
2106 ASSERT(!result.isRectBasedTest() || request.listBased()); 2106 ASSERT(!result.isRectBasedTest() || result.hitTestRequest().listBased()) ;
2107 if (request.listBased()) 2107 if (result.hitTestRequest().listBased())
2108 result.append(tempResult, request); 2108 result.append(tempResult);
2109 2109
2110 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedT ransformState)) { 2110 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedT ransformState)) {
2111 resultLayer = hitLayer; 2111 resultLayer = hitLayer;
2112 if (!request.listBased()) 2112 if (!result.hitTestRequest().listBased())
2113 result = tempResult; 2113 result = tempResult;
2114 if (!depthSortDescendants) 2114 if (!depthSortDescendants)
2115 break; 2115 break;
2116 } 2116 }
2117 } 2117 }
2118 2118
2119 return resultLayer; 2119 return resultLayer;
2120 } 2120 }
2121 2121
2122 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestPaginatedChildLayer(Deprecate dPaintLayer* childLayer, DeprecatedPaintLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, 2122 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestPaginatedChildLayer(Deprecate dPaintLayer* childLayer, DeprecatedPaintLayer* rootLayer, HitTestResult& result,
2123 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset) 2123 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
2124 { 2124 {
2125 Vector<DeprecatedPaintLayer*> columnLayers; 2125 Vector<DeprecatedPaintLayer*> columnLayers;
2126 DeprecatedPaintLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlo wOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode (); 2126 DeprecatedPaintLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlo wOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode ();
2127 for (DeprecatedPaintLayer* curr = childLayer->parent(); curr; curr = curr->p arent()) { 2127 for (DeprecatedPaintLayer* curr = childLayer->parent(); curr; curr = curr->p arent()) {
2128 if (curr->layoutObject()->hasColumns() && checkContainingBlockChainForPa gination(childLayer->layoutObject(), curr->layoutBox())) 2128 if (curr->layoutObject()->hasColumns() && checkContainingBlockChainForPa gination(childLayer->layoutObject(), curr->layoutBox()))
2129 columnLayers.append(curr); 2129 columnLayers.append(curr);
2130 if (curr->stackingNode() == ancestorNode) 2130 if (curr->stackingNode() == ancestorNode)
2131 break; 2131 break;
2132 } 2132 }
2133 2133
2134 ASSERT(columnLayers.size()); 2134 ASSERT(columnLayers.size());
2135 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitT estRect, hitTestLocation, transformState, zOffset, 2135 return hitTestChildLayerColumns(childLayer, rootLayer, result, hitTestRect, hitTestLocation, transformState, zOffset,
2136 columnLayers, columnLayers.size() - 1); 2136 columnLayers, columnLayers.size() - 1);
2137 } 2137 }
2138 2138
2139 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestChildLayerColumns(DeprecatedP aintLayer* childLayer, DeprecatedPaintLayer* rootLayer, const HitTestRequest& re quest, HitTestResult& result, 2139 DeprecatedPaintLayer* DeprecatedPaintLayer::hitTestChildLayerColumns(DeprecatedP aintLayer* childLayer, DeprecatedPaintLayer* rootLayer, HitTestResult& result,
2140 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset, 2140 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
2141 const Vector<DeprecatedPaintLayer*>& columnLayers, size_t columnIndex) 2141 const Vector<DeprecatedPaintLayer*>& columnLayers, size_t columnIndex)
2142 { 2142 {
2143 LayoutBlock* columnBlock = toLayoutBlock(columnLayers[columnIndex]->layoutOb ject()); 2143 LayoutBlock* columnBlock = toLayoutBlock(columnLayers[columnIndex]->layoutOb ject());
2144 2144
2145 ASSERT(columnBlock && columnBlock->hasColumns()); 2145 ASSERT(columnBlock && columnBlock->hasColumns());
2146 if (!columnBlock || !columnBlock->hasColumns()) 2146 if (!columnBlock || !columnBlock->hasColumns())
2147 return 0; 2147 return 0;
2148 2148
2149 LayoutPoint layerOffset; 2149 LayoutPoint layerOffset;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
2199 if (!columnIndex) { 2199 if (!columnIndex) {
2200 // Apply a translation transform to change where the layer paint s. 2200 // Apply a translation transform to change where the layer paint s.
2201 TransformationMatrix oldTransform; 2201 TransformationMatrix oldTransform;
2202 bool oldHasTransform = childLayer->transform(); 2202 bool oldHasTransform = childLayer->transform();
2203 if (oldHasTransform) 2203 if (oldHasTransform)
2204 oldTransform = *childLayer->transform(); 2204 oldTransform = *childLayer->transform();
2205 TransformationMatrix newTransform(oldTransform); 2205 TransformationMatrix newTransform(oldTransform);
2206 newTransform.translateRight(offset.width(), offset.height()); 2206 newTransform.translateRight(offset.width(), offset.height());
2207 2207
2208 childLayer->m_transform = adoptPtr(new TransformationMatrix(newT ransform)); 2208 childLayer->m_transform = adoptPtr(new TransformationMatrix(newT ransform));
2209 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestLocation, false, transformState, zOffset) ; 2209 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], result, localClipRect, hitTestLocation, false, transformState, zOffset);
2210 if (oldHasTransform) 2210 if (oldHasTransform)
2211 childLayer->m_transform = adoptPtr(new TransformationMatrix( oldTransform)); 2211 childLayer->m_transform = adoptPtr(new TransformationMatrix( oldTransform));
2212 else 2212 else
2213 childLayer->m_transform.clear(); 2213 childLayer->m_transform.clear();
2214 } else { 2214 } else {
2215 // Adjust the transform such that the renderer's upper left corn er will be at (0,0) in user space. 2215 // Adjust the transform such that the renderer's upper left corn er will be at (0,0) in user space.
2216 // This involves subtracting out the position of the layer in ou r current coordinate space. 2216 // This involves subtracting out the position of the layer in ou r current coordinate space.
2217 DeprecatedPaintLayer* nextLayer = columnLayers[columnIndex - 1]; 2217 DeprecatedPaintLayer* nextLayer = columnLayers[columnIndex - 1];
2218 RefPtr<HitTestingTransformState> newTransformState = nextLayer-> createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState); 2218 RefPtr<HitTestingTransformState> newTransformState = nextLayer-> createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState);
2219 newTransformState->translate(offset.width(), offset.height(), Hi tTestingTransformState::AccumulateTransform); 2219 newTransformState->translate(offset.width(), offset.height(), Hi tTestingTransformState::AccumulateTransform);
2220 FloatPoint localPoint = newTransformState->mappedPoint(); 2220 FloatPoint localPoint = newTransformState->mappedPoint();
2221 FloatQuad localPointQuad = newTransformState->mappedQuad(); 2221 FloatQuad localPointQuad = newTransformState->mappedQuad();
2222 LayoutRect localHitTestRect(newTransformState->mappedArea().encl osingBoundingBox()); 2222 LayoutRect localHitTestRect(newTransformState->mappedArea().encl osingBoundingBox());
2223 HitTestLocation newHitTestLocation; 2223 HitTestLocation newHitTestLocation;
2224 if (hitTestLocation.isRectBasedTest()) 2224 if (hitTestLocation.isRectBasedTest())
2225 newHitTestLocation = HitTestLocation(localPoint, localPointQ uad); 2225 newHitTestLocation = HitTestLocation(localPoint, localPointQ uad);
2226 else 2226 else
2227 newHitTestLocation = HitTestLocation(localPoint); 2227 newHitTestLocation = HitTestLocation(localPoint);
2228 newTransformState->flatten(); 2228 newTransformState->flatten();
2229 2229
2230 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[col umnIndex - 1], request, result, localHitTestRect, newHitTestLocation, 2230 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[col umnIndex - 1], result, localHitTestRect, newHitTestLocation,
2231 newTransformState.get(), zOffset, columnLayers, columnIndex - 1); 2231 newTransformState.get(), zOffset, columnLayers, columnIndex - 1);
2232 } 2232 }
2233 2233
2234 if (hitLayer) 2234 if (hitLayer)
2235 return hitLayer; 2235 return hitLayer;
2236 } 2236 }
2237 } 2237 }
2238 2238
2239 return 0; 2239 return 0;
2240 } 2240 }
(...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after
2968 } 2968 }
2969 } 2969 }
2970 2970
2971 void showLayerTree(const blink::LayoutObject* renderer) 2971 void showLayerTree(const blink::LayoutObject* renderer)
2972 { 2972 {
2973 if (!renderer) 2973 if (!renderer)
2974 return; 2974 return;
2975 showLayerTree(renderer->enclosingLayer()); 2975 showLayerTree(renderer->enclosingLayer());
2976 } 2976 }
2977 #endif 2977 #endif
OLDNEW
« no previous file with comments | « Source/core/paint/DeprecatedPaintLayer.h ('k') | Source/core/testing/Internals.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698