2008-11-12 Simon Fraser <simon.fraser@apple.com>
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Nov 2008 23:43:52 +0000 (23:43 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Nov 2008 23:43:52 +0000 (23:43 +0000)
        Reviewed by Dave Hyatt

        https://bugs.webkit.org/show_bug.cgi?id=21942
        https://bugs.webkit.org/show_bug.cgi?id=18557

        Add methods which can be used to map renderer-local rectangles
        to quads in absolute coordinates, taking transforms into account:
            localToAbsoluteQuad() converts a local rect into an absolute quad.
            collectAbsoluteLineBoxQuads() is an analogue of addLineBoxRects()
                that works with quads.
            absoluteQuads() is an analogue of absoluteRects(), for quads.

        Use the quad methods to fix the inspector highlight for transformed
        elements.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@38346 268f45cc-cd09-0410-ab3c-d52691b4dbfc

43 files changed:
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.pro
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/WebCoreSources.bkl
WebCore/inspector/InspectorController.cpp
WebCore/platform/graphics/AffineTransform.cpp
WebCore/platform/graphics/AffineTransform.h
WebCore/platform/graphics/FloatQuad.cpp [new file with mode: 0644]
WebCore/platform/graphics/FloatQuad.h [new file with mode: 0644]
WebCore/rendering/RenderBox.cpp
WebCore/rendering/RenderBox.h
WebCore/rendering/RenderContainer.cpp
WebCore/rendering/RenderContainer.h
WebCore/rendering/RenderInline.cpp
WebCore/rendering/RenderInline.h
WebCore/rendering/RenderObject.cpp
WebCore/rendering/RenderObject.h
WebCore/rendering/RenderPath.cpp
WebCore/rendering/RenderPath.h
WebCore/rendering/RenderSVGContainer.cpp
WebCore/rendering/RenderSVGContainer.h
WebCore/rendering/RenderSVGHiddenContainer.cpp
WebCore/rendering/RenderSVGHiddenContainer.h
WebCore/rendering/RenderSVGImage.cpp
WebCore/rendering/RenderSVGImage.h
WebCore/rendering/RenderSVGInlineText.cpp
WebCore/rendering/RenderSVGInlineText.h
WebCore/rendering/RenderSVGRoot.cpp
WebCore/rendering/RenderSVGRoot.h
WebCore/rendering/RenderSVGTSpan.cpp
WebCore/rendering/RenderSVGTSpan.h
WebCore/rendering/RenderSVGText.cpp
WebCore/rendering/RenderSVGText.h
WebCore/rendering/RenderSVGTextPath.cpp
WebCore/rendering/RenderSVGTextPath.h
WebCore/rendering/RenderTableCell.cpp
WebCore/rendering/RenderTableCell.h
WebCore/rendering/RenderText.cpp
WebCore/rendering/RenderText.h
WebCore/rendering/RenderView.cpp
WebCore/rendering/RenderView.h

index 6e51c26..e6c36bb 100644 (file)
@@ -1,3 +1,115 @@
+2008-11-12  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Dave Hyatt
+
+        https://bugs.webkit.org/show_bug.cgi?id=21942
+        https://bugs.webkit.org/show_bug.cgi?id=18557
+        
+        Add methods which can be used to map renderer-local rectangles
+        to quads in absolute coordinates, taking transforms into account:
+            localToAbsoluteQuad() converts a local rect into an absolute quad.
+            collectAbsoluteLineBoxQuads() is an analogue of addLineBoxRects()
+                that works with quads.
+            absoluteQuads() is an analogue of absoluteRects(), for quads.
+        
+        Use the quad methods to fix the inspector highlight for transformed
+        elements.
+
+        * GNUmakefile.am:
+        * WebCore.pro:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * WebCoreSources.bkl:
+        * inspector/InspectorController.cpp:
+        (WebCore::drawOutlinedQuad):
+        (WebCore::drawHighlightForBoxes):
+        (WebCore::frameToMainFrameOffset):
+        (WebCore::InspectorController::drawNodeHighlight):
+        * platform/graphics/AffineTransform.cpp:
+        (WebCore::AffineTransform::mapQuad):
+        * platform/graphics/AffineTransform.h:
+        * platform/graphics/FloatQuad.cpp: Added.
+        (WebCore::min4):
+        (WebCore::max4):
+        (WebCore::FloatQuad::boundingBox):
+        * platform/graphics/FloatQuad.h: Added.
+        (WebCore::FloatQuad::FloatQuad):
+        (WebCore::FloatQuad::p1):
+        (WebCore::FloatQuad::p2):
+        (WebCore::FloatQuad::p3):
+        (WebCore::FloatQuad::p4):
+        (WebCore::FloatQuad::setP1):
+        (WebCore::FloatQuad::setP2):
+        (WebCore::FloatQuad::setP3):
+        (WebCore::FloatQuad::setP4):
+        (WebCore::FloatQuad::isEmpty):
+        (WebCore::FloatQuad::enclosingBoundingBox):
+        (WebCore::FloatQuad::move):
+        (WebCore::operator+=):
+        (WebCore::operator-=):
+        (WebCore::operator==):
+        (WebCore::operator!=):
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::localToAbsoluteQuad):
+        * rendering/RenderBox.h:
+        * rendering/RenderContainer.cpp:
+        (WebCore::RenderContainer::collectAbsoluteLineBoxQuads):
+        * rendering/RenderContainer.h:
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::absoluteQuads):
+        * rendering/RenderInline.h:
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::absoluteBoundingBoxRect):
+        (WebCore::RenderObject::collectAbsoluteLineBoxQuads):
+        (WebCore::RenderObject::absoluteQuads):
+        (WebCore::RenderObject::localToAbsoluteQuad):
+        (WebCore::RenderObject::absoluteContentQuad):
+        * rendering/RenderObject.h:
+        * rendering/RenderPath.cpp:
+        (WebCore::RenderPath::absoluteQuads):
+        * rendering/RenderPath.h:
+        * rendering/RenderSVGContainer.cpp:
+        (WebCore::RenderSVGContainer::absoluteQuads):
+        * rendering/RenderSVGContainer.h:
+        * rendering/RenderSVGHiddenContainer.cpp:
+        (WebCore::RenderSVGHiddenContainer::absoluteQuads):
+        * rendering/RenderSVGHiddenContainer.h:
+        * rendering/RenderSVGImage.cpp:
+        (WebCore::RenderSVGImage::calculateAbsoluteBounds):
+        (WebCore::RenderSVGImage::absoluteQuads):
+        * rendering/RenderSVGImage.h:
+        * rendering/RenderSVGInlineText.cpp:
+        (WebCore::RenderSVGInlineText::absoluteQuads):
+        (WebCore::RenderSVGInlineText::computeAbsoluteRectForRange):
+        * rendering/RenderSVGInlineText.h:
+        * rendering/RenderSVGRoot.cpp:
+        (WebCore::RenderSVGRoot::absoluteQuads):
+        * rendering/RenderSVGRoot.h:
+        * rendering/RenderSVGTSpan.cpp:
+        (WebCore::RenderSVGTSpan::absoluteRects):
+        (WebCore::RenderSVGTSpan::absoluteQuads):
+        * rendering/RenderSVGTSpan.h:
+        * rendering/RenderSVGText.cpp:
+        (WebCore::RenderSVGText::absoluteRects):
+        (WebCore::RenderSVGText::absoluteQuads):
+        * rendering/RenderSVGText.h:
+        * rendering/RenderSVGTextPath.cpp:
+        (WebCore::RenderSVGTextPath::absoluteRects):
+        (WebCore::RenderSVGTextPath::absoluteQuads):
+        * rendering/RenderSVGTextPath.h:
+        * rendering/RenderTableCell.cpp:
+        (WebCore::RenderTableCell::localToAbsolute):
+        (WebCore::RenderTableCell::localToAbsoluteQuad):
+        * rendering/RenderTableCell.h:
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::absoluteQuads):
+        (WebCore::RenderText::collectAbsoluteLineBoxQuads):
+        * rendering/RenderText.h:
+        * rendering/RenderView.cpp:
+        (WebCore::RenderView::localToAbsoluteQuad):
+        (WebCore::RenderView::absoluteQuads):
+        * rendering/RenderView.h:
+
 2008-11-12  Brent Fulgham <bfulgham@gmail.com>
 
         Fix Bug 22178: Build errors in WebKit Cairo port
index a77a211..91fa52a 100644 (file)
@@ -1240,6 +1240,7 @@ webcore_sources += \
        WebCore/platform/graphics/FloatPoint.h \
        WebCore/platform/graphics/FloatPoint3D.cpp \
        WebCore/platform/graphics/FloatPoint3D.h \
+       WebCore/platform/graphics/FloatQuad.cpp \
        WebCore/platform/graphics/FloatRect.cpp \
        WebCore/platform/graphics/FloatRect.h \
        WebCore/platform/graphics/FloatSize.cpp \
index 457f00d..0e21505 100644 (file)
@@ -824,6 +824,7 @@ SOURCES += \
     platform/graphics/Color.cpp \
     platform/graphics/FloatPoint3D.cpp \
     platform/graphics/FloatPoint.cpp \
+    platform/graphics/FloatQuad.cpp \
     platform/graphics/FloatRect.cpp \
     platform/graphics/FloatSize.cpp \
     platform/graphics/FontData.cpp \
index 8d317cb..d614f88 100644 (file)
                                        >\r
                                </File>\r
                                <File\r
+                                       RelativePath="..\platform\graphics\FloatQuad.cpp"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="..\platform\graphics\FloatQuad.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath="..\platform\graphics\FloatRect.cpp"\r
                                        >\r
                                </File>\r
index b208893..76837c9 100644 (file)
@@ -45,6 +45,8 @@
                0F56028F0E4B76580065B038 /* RenderMarquee.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F56028D0E4B76580065B038 /* RenderMarquee.h */; };
                0F5602900E4B76580065B038 /* RenderMarquee.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F56028E0E4B76580065B038 /* RenderMarquee.cpp */; };
                0FC705210EB1815600B90AD8 /* AtomicStringHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC705200EB1815600B90AD8 /* AtomicStringHash.h */; };
+               0FD723820EC8BD9300CA5DD7 /* FloatQuad.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD723800EC8BD9300CA5DD7 /* FloatQuad.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FD723830EC8BD9300CA5DD7 /* FloatQuad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD723810EC8BD9300CA5DD7 /* FloatQuad.cpp */; };
                1402645E0AFDC19B005919E2 /* LoggingMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1402645D0AFDC19B005919E2 /* LoggingMac.mm */; };
                1403B99709EB13AF00797C7F /* DOMWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 1403B99509EB13AF00797C7F /* DOMWindow.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1403B99809EB13AF00797C7F /* DOMWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1403B99609EB13AF00797C7F /* DOMWindow.cpp */; };
                0F56028D0E4B76580065B038 /* RenderMarquee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderMarquee.h; sourceTree = "<group>"; };
                0F56028E0E4B76580065B038 /* RenderMarquee.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMarquee.cpp; sourceTree = "<group>"; };
                0FC705200EB1815600B90AD8 /* AtomicStringHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AtomicStringHash.h; sourceTree = "<group>"; };
+               0FD723800EC8BD9300CA5DD7 /* FloatQuad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatQuad.h; sourceTree = "<group>"; };
+               0FD723810EC8BD9300CA5DD7 /* FloatQuad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FloatQuad.cpp; sourceTree = "<group>"; };
                1402645D0AFDC19B005919E2 /* LoggingMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = LoggingMac.mm; sourceTree = "<group>"; };
                1403B90C09EB124500797C7F /* DOMWindow.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DOMWindow.idl; sourceTree = "<group>"; };
                1403B99509EB13AF00797C7F /* DOMWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMWindow.h; sourceTree = "<group>"; };
                                B275353B0B053814002CE64F /* FloatPoint.h */,
                                B2E27C9D0B0F2B0900F17C7B /* FloatPoint3D.cpp */,
                                B2E27C9E0B0F2B0900F17C7B /* FloatPoint3D.h */,
+                               0FD723810EC8BD9300CA5DD7 /* FloatQuad.cpp */,
+                               0FD723800EC8BD9300CA5DD7 /* FloatQuad.h */,
                                B275353C0B053814002CE64F /* FloatRect.cpp */,
                                B275353D0B053814002CE64F /* FloatRect.h */,
                                B275353E0B053814002CE64F /* FloatSize.cpp */,
                                0FC705210EB1815600B90AD8 /* AtomicStringHash.h in Headers */,
                                E11C9D9B0EB3681200E409DB /* ScriptExecutionContext.h in Headers */,
                                E1A643F20EC0972500779668 /* WorkerScriptController.h in Headers */,
+                               0FD723820EC8BD9300CA5DD7 /* FloatQuad.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                E1C36CBD0EB08062007410BC /* JSDOMGlobalObject.cpp in Sources */,
                                E11C9DB00EB3699500E409DB /* ScriptExecutionContext.cpp in Sources */,
                                E1A643FD0EC097A000779668 /* WorkerScriptController.cpp in Sources */,
+                               0FD723830EC8BD9300CA5DD7 /* FloatQuad.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index a566682..30c9d29 100644 (file)
@@ -744,6 +744,7 @@ This file contains the list of files needed to build WebCore.
         platform/graphics/BitmapImage.cpp
         platform/graphics/Color.cpp
         platform/graphics/FloatPoint.cpp
+        platform/graphics/FloatQuad.cpp
         platform/graphics/FloatRect.cpp
         platform/graphics/FloatSize.cpp
         platform/graphics/GeneratedImage.cpp
index 109464a..91127d1 100644 (file)
@@ -2637,44 +2637,69 @@ void InspectorController::removeBreakpoint(intptr_t sourceID, unsigned lineNumbe
 }
 #endif
 
-static void drawOutlinedRect(GraphicsContext& context, const IntRect& rect, const Color& fillColor)
+static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
 {
-    static const int outlineThickness = 1;
+    static const int outlineThickness = 2;
     static const Color outlineColor(62, 86, 180, 228);
 
-    IntRect outline = rect;
-    outline.inflate(outlineThickness);
+    Path quadPath;
+    quadPath.moveTo(quad.p1());
+    quadPath.addLineTo(quad.p2());
+    quadPath.addLineTo(quad.p3());
+    quadPath.addLineTo(quad.p4());
+    quadPath.closeSubpath();
+    
+    // Clear the quad
+    {
+        context.save();
+        context.setCompositeOperation(CompositeClear);
+        context.addPath(quadPath);
+        context.fillPath();
+        context.restore();
+    }
 
-    context.clearRect(outline);
+    // Clip out the quad, then draw with a 2px stroke to get a pixel
+    // of outline (because inflating a quad is hard)
+    {
+        context.save();
+        context.addPath(quadPath);
+        context.clipOut(quadPath);
 
-    context.save();
-    context.clipOut(rect);
-    context.fillRect(outline, outlineColor);
-    context.restore();
+        context.addPath(quadPath);
+        context.setStrokeThickness(outlineThickness);
+        context.setStrokeColor(outlineColor);
+        context.strokePath();
 
-    context.fillRect(rect, fillColor);
+        context.restore();
+    }
+    
+    // Now do the fill
+    context.addPath(quadPath);
+    context.setFillColor(fillColor);
+    context.fillPath();
 }
 
-static void drawHighlightForBoxes(GraphicsContext& context, const Vector<IntRect>& lineBoxRects, const IntRect& contentBox, const IntRect& paddingBox, const IntRect& borderBox, const IntRect& marginBox)
+static void drawHighlightForBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
 {
     static const Color contentBoxColor(125, 173, 217, 128);
     static const Color paddingBoxColor(125, 173, 217, 160);
     static const Color borderBoxColor(125, 173, 217, 192);
     static const Color marginBoxColor(125, 173, 217, 228);
 
-    if (!lineBoxRects.isEmpty()) {
-        for (size_t i = 0; i < lineBoxRects.size(); ++i)
-            drawOutlinedRect(context, lineBoxRects[i], contentBoxColor);
+    if (!lineBoxQuads.isEmpty()) {
+        for (size_t i = 0; i < lineBoxQuads.size(); ++i)
+            drawOutlinedQuad(context, lineBoxQuads[i], contentBoxColor);
         return;
     }
 
-    if (marginBox != borderBox)
-        drawOutlinedRect(context, marginBox, marginBoxColor);
-    if (borderBox != paddingBox)
-        drawOutlinedRect(context, borderBox, borderBoxColor);
-    if (paddingBox != contentBox)
-        drawOutlinedRect(context, paddingBox, paddingBoxColor);
-    drawOutlinedRect(context, contentBox, contentBoxColor);
+    if (marginQuad != borderQuad)
+        drawOutlinedQuad(context, marginQuad, marginBoxColor);
+    if (borderQuad != paddingQuad)
+        drawOutlinedQuad(context, borderQuad, borderBoxColor);
+    if (paddingQuad != contentQuad)
+        drawOutlinedQuad(context, paddingQuad, paddingBoxColor);
+
+    drawOutlinedQuad(context, contentQuad, contentBoxColor);
 }
 
 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
@@ -2682,6 +2707,12 @@ static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
 }
 
+static inline IntSize frameToMainFrameOffset(Frame* frame)
+{
+    IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
+    return mainFramePoint - IntPoint();
+}
+
 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
 {
     if (!m_highlightedNode)
@@ -2692,35 +2723,47 @@ void InspectorController::drawNodeHighlight(GraphicsContext& context) const
     if (!renderer || !containingFrame)
         return;
 
-    IntRect contentBox = renderer->absoluteContentBox();
-    IntRect boundingBox = renderer->absoluteBoundingBoxRect();
+    IntRect contentBox = renderer->contentBox();
 
     // FIXME: Should we add methods to RenderObject to obtain these rects?
-    IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(), contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom());
-    IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(), paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom());
-    IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(), borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom());
+    IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(),
+                       contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom());
+    IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(),
+                      paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom());
+    IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(),
+                      borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom());
+
+
+    IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
+
+    FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
+    FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
+    FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
+    FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
+
+    absContentQuad.move(mainFrameOffset);
+    absPaddingQuad.move(mainFrameOffset);
+    absBorderQuad.move(mainFrameOffset);
+    absMarginQuad.move(mainFrameOffset);
 
-    convertFromFrameToMainFrame(containingFrame, contentBox);
-    convertFromFrameToMainFrame(containingFrame, paddingBox);
-    convertFromFrameToMainFrame(containingFrame, borderBox);
-    convertFromFrameToMainFrame(containingFrame, marginBox);
-    convertFromFrameToMainFrame(containingFrame, boundingBox);
+    IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
+    boundingBox.move(mainFrameOffset);
 
-    Vector<IntRect> lineBoxRects;
+    Vector<FloatQuad> lineBoxQuads;
     if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) {
         // FIXME: We should show margins/padding/border for inlines.
-        renderer->addLineBoxRects(lineBoxRects);
+        renderer->collectAbsoluteLineBoxQuads(lineBoxQuads);
     }
 
-    for (unsigned i = 0; i < lineBoxRects.size(); ++i)
-        convertFromFrameToMainFrame(containingFrame, lineBoxRects[i]);
+    for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
+        lineBoxQuads[i] += mainFrameOffset;
 
-    if (lineBoxRects.isEmpty() && contentBox.isEmpty()) {
+    if (lineBoxQuads.isEmpty() && contentBox.isEmpty()) {
         // If we have no line boxes and our content box is empty, we'll just draw our bounding box.
         // This can happen, e.g., with an <a> enclosing an <img style="float:right">.
         // FIXME: Can we make this better/more accurate? The <a> in the above case has no
         // width/height but the highlight makes it appear to be the size of the <img>.
-        lineBoxRects.append(boundingBox);
+        lineBoxQuads.append(FloatRect(boundingBox));
     }
 
     ASSERT(m_inspectedPage);
@@ -2739,7 +2782,7 @@ void InspectorController::drawNodeHighlight(GraphicsContext& context) const
 
     context.translate(-overlayRect.x(), -overlayRect.y());
 
-    drawHighlightForBoxes(context, lineBoxRects, contentBox, paddingBox, borderBox, marginBox);
+    drawHighlightForBoxes(context, lineBoxQuads, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
 }
 
 void InspectorController::count(const UString& title, unsigned lineNumber, const String& sourceID)
index fdeba44..cba0bab 100644 (file)
@@ -27,6 +27,7 @@
 #include "AffineTransform.h"
 
 #include "FloatRect.h"
+#include "FloatQuad.h"
 #include "IntRect.h"
 
 #include <wtf/MathExtras.h>
@@ -160,6 +161,16 @@ FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
     return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
 }
 
+FloatQuad AffineTransform::mapQuad(const FloatQuad& quad) const
+{
+    // FIXME: avoid 4 seperate library calls. Point mapping really needs
+    // to be platform-independent code.
+    return FloatQuad(mapPoint(quad.p1()),
+                     mapPoint(quad.p2()),
+                     mapPoint(quad.p3()),
+                     mapPoint(quad.p4()));
+}
+
 void AffineTransform::blend(const AffineTransform& from, double progress)
 {
     double srA[9], srB[9];
index 352a592..e2567e6 100644 (file)
@@ -50,6 +50,7 @@ class IntPoint;
 class IntRect;
 class FloatPoint;
 class FloatRect;
+class FloatQuad;
 
 class AffineTransform {
 public:
@@ -73,6 +74,8 @@ public:
 
     FloatRect mapRect(const FloatRect&) const;
 
+    FloatQuad mapQuad(const FloatQuad&) const;
+
     bool isIdentity() const;
 
     double a() const;
diff --git a/WebCore/platform/graphics/FloatQuad.cpp b/WebCore/platform/graphics/FloatQuad.cpp
new file mode 100644 (file)
index 0000000..68c24ea
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FloatQuad.h"
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+static inline float min4(float a, float b, float c, float d)
+{
+    return min(min(a, b), min(c, d));
+}
+
+static inline float max4(float a, float b, float c, float d)
+{
+    return max(max(a, b), max(c, d));
+}
+
+FloatRect FloatQuad::boundingBox() const
+{
+    float left   = min4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x());
+    float top    = min4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y());
+
+    float right  = max4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x());
+    float bottom = max4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y());
+    
+    return FloatRect(left, top, right - left, bottom - top);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/FloatQuad.h b/WebCore/platform/graphics/FloatQuad.h
new file mode 100644 (file)
index 0000000..e05b27d
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FloatQuad_h
+#define FloatQuad_h
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+
+namespace WebCore {
+
+// A FloatQuad is a collection of 4 points, often representing the result of
+// mapping a rectangle through transforms. When initialized from a rect, the
+// points are in clockwise order from top left.
+class FloatQuad {
+public:
+    FloatQuad()
+    {
+    }
+
+    FloatQuad(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3, const FloatPoint& p4)
+        : m_p1(p1)
+        , m_p2(p2)
+        , m_p3(p3)
+        , m_p4(p4)
+    {
+    }
+
+    FloatQuad(const FloatRect& inRect)
+        : m_p1(inRect.location())
+        , m_p2(inRect.right(), inRect.y())
+        , m_p3(inRect.right(), inRect.bottom())
+        , m_p4(inRect.x(), inRect.bottom())
+    {
+    }
+
+    FloatPoint p1() const { return m_p1; }
+    FloatPoint p2() const { return m_p2; }
+    FloatPoint p3() const { return m_p3; }
+    FloatPoint p4() const { return m_p4; }
+
+    void setP1(const FloatPoint& p) { m_p1 = p; }
+    void setP2(const FloatPoint& p) { m_p2 = p; }
+    void setP3(const FloatPoint& p) { m_p3 = p; }
+    void setP4(const FloatPoint& p) { m_p4 = p; }
+
+    // isEmpty tests that the bounding box is empty. This will not identify
+    // "slanted" empty quads.
+    bool isEmpty() const { return boundingBox().isEmpty(); }
+
+    FloatRect boundingBox() const;
+    IntRect enclosingBoundingBox() const
+    {
+        return enclosingIntRect(boundingBox());
+    }
+
+    void move(const FloatSize& offset)
+    {
+        m_p1 += offset;
+        m_p2 += offset;
+        m_p3 += offset;
+        m_p4 += offset;
+    }
+
+    void move(float dx, float dy)
+    {
+        m_p1.move(dx, dy);
+        m_p2.move(dx, dy);
+        m_p3.move(dx, dy);
+        m_p4.move(dx, dy);
+    }
+
+private:
+    FloatPoint m_p1;
+    FloatPoint m_p2;
+    FloatPoint m_p3;
+    FloatPoint m_p4;
+};
+
+inline FloatQuad& operator+=(FloatQuad& a, const FloatSize& b)
+{
+    a.move(b);
+    return a;
+}
+
+inline FloatQuad& operator-=(FloatQuad& a, const FloatSize& b)
+{
+    a.move(-b.width(), -b.height());
+    return a;
+}
+
+inline bool operator==(const FloatQuad& a, const FloatQuad& b)
+{
+    return a.p1() == b.p1() &&
+           a.p2() == b.p2() && 
+           a.p3() == b.p3() &&
+           a.p4() == b.p4();
+}
+
+inline bool operator!=(const FloatQuad& a, const FloatQuad& b)
+{
+    return a.p1() != b.p1() ||
+           a.p2() != b.p2() || 
+           a.p3() != b.p3() ||
+           a.p4() != b.p4();
+}
+
+}   // namespace WebCore
+
+
+#endif // FloatQuad_h
+
index 95a8026..5f51eb3 100644 (file)
@@ -1052,6 +1052,34 @@ FloatPoint RenderBox::absoluteToLocal(FloatPoint containerPoint, bool fixed, boo
     return FloatPoint();
 }
 
+FloatQuad RenderBox::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+    // We don't expect localToAbsoluteQuad() to be called during layout (yet)
+    ASSERT(!view() || !view()->layoutState());
+
+    if (style()->position() == FixedPosition)
+        fixed = true;
+
+    RenderObject* o = container();
+    if (o) {
+        FloatQuad quad = localQuad;
+        if (m_layer && m_layer->transform()) {
+            fixed = false;  // Elements with transforms act as a containing block for fixed position descendants
+            quad = m_layer->transform()->mapQuad(quad);
+        }
+
+        quad += offsetFromContainer(o);
+
+        // Take into account space above a vertically aligned table cell
+        // (see localToAbsoluteForContent())
+        quad.move(0.0f, static_cast<float>(borderTopExtra()));
+
+        return o->localToAbsoluteQuad(quad, fixed);
+    }
+    
+    return FloatQuad();
+}
+
 IntSize RenderBox::offsetFromContainer(RenderObject* o) const
 {
     ASSERT(o == container());
index 3cc8be7..ded9cb5 100644 (file)
@@ -51,6 +51,7 @@ public:
 
     virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
     virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+    virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
 
     virtual int xPos() const { return m_x; }
     virtual int yPos() const { return m_y; }
index 8c3bbca..042f5aa 100644 (file)
@@ -679,6 +679,23 @@ void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, un
     }
 }
 
+void RenderContainer::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight)
+{
+    if (!m_firstChild && (isInline() || isAnonymousBlock())) {
+        absoluteQuads(quads);
+        return;
+    }
+
+    if (!m_firstChild)
+        return;
+
+    unsigned offset = start;
+    for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) {
+        if (child->isText() || child->isInline() || child->isAnonymousBlock())
+            child->absoluteQuads(quads);
+    }
+}
+
 #undef DEBUG_LAYOUT
 
 } // namespace WebCore
index db0a96e..68aba84 100644 (file)
@@ -63,6 +63,7 @@ public:
     virtual VisiblePosition positionForCoordinates(int x, int y);
 
     virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+    virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
 
 private:
     RenderObject* m_firstChild;
index 79d914f..40e5029 100644 (file)
@@ -301,6 +301,22 @@ void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool to
                                       topLevel);
 }
 
+void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+        FloatRect localRect(curr->xPos(), curr->yPos(), curr->width(), curr->height());
+        quads.append(localToAbsoluteQuad(localRect));
+    }
+    
+    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (!curr->isText())
+            curr->absoluteQuads(quads, false);
+    }
+
+    if (continuation() && topLevel)
+        continuation()->absoluteQuads(quads, topLevel);
+}
+
 bool RenderInline::requiresLayer()
 {
     return isRelPositioned() || isTransparent() || hasMask();
index 36cb864..1c42a6f 100644 (file)
@@ -68,6 +68,7 @@ public:
     virtual int offsetTop() const;
 
     void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
 
     virtual VisiblePosition positionForCoordinates(int x, int y);
 
index a7f722b..9cbc327 100644 (file)
@@ -1704,9 +1704,22 @@ void RenderObject::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool to
         rects.append(IntRect(tx, ty, width(), height() + borderTopExtra() + borderBottomExtra()));
 }
 
-IntRect RenderObject::absoluteBoundingBoxRect()
+IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms)
 {
-    // FIXME: This doesn't work correctly with transforms.
+    if (useTransforms) {
+        Vector<FloatQuad> quads;
+        absoluteQuads(quads);
+
+        size_t n = quads.size();
+        if (!n)
+            return IntRect();
+    
+        IntRect result = quads[0].enclosingBoundingBox();
+        for (size_t i = 1; i < n; ++i)
+            result.unite(quads[i].enclosingBoundingBox());
+        return result;
+    }
+
     FloatPoint absPos = localToAbsolute();
     Vector<IntRect> rects;
     absoluteRects(rects, absPos.x(), absPos.y());
@@ -1721,6 +1734,24 @@ IntRect RenderObject::absoluteBoundingBoxRect()
     return result;
 }
 
+void RenderObject::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned startOffset, unsigned endOffset, bool useSelectionHeight)
+{
+}
+
+void RenderObject::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    // For blocks inside inlines, we go ahead and include margins so that we run right up to the
+    // inline boxes above and below us (thus getting merged with them to form a single irregular
+    // shape).
+    if (topLevel && continuation()) {
+        FloatRect localRect(0, -collapsedMarginTop(),
+                            width(), height() + collapsedMarginTop() + collapsedMarginBottom());
+        quads.append(localToAbsoluteQuad(localRect));
+        continuation()->absoluteQuads(quads, topLevel);
+    } else
+        quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height() + borderTopExtra() + borderBottomExtra())));
+}
+
 void RenderObject::addAbsoluteRectForLayer(IntRect& result)
 {
     if (hasLayer())
@@ -2398,6 +2429,20 @@ FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed,
     return FloatPoint();
 }
 
+FloatQuad RenderObject::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+    RenderObject* o = parent();
+    if (o) {
+        FloatQuad quad = localQuad;
+        quad.move(0.0f, static_cast<float>(o->borderTopExtra()));
+        if (o->hasOverflowClip())
+            quad -= o->layer()->scrolledContentOffset();
+        return o->localToAbsoluteQuad(quad, fixed);
+    }
+
+    return FloatQuad();
+}
+
 IntRect RenderObject::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
 {
    if (extraWidthToEndOfLine)
@@ -3070,6 +3115,12 @@ IntRect RenderObject::absoluteContentBox() const
     return rect;
 }
 
+FloatQuad RenderObject::absoluteContentQuad() const
+{
+    IntRect rect = contentBox();
+    return localToAbsoluteQuad(FloatRect(rect));
+}
+
 void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const
 {
     int outlineSize = !isInline() && continuation() ? continuation()->style()->outlineSize() : style()->outlineSize();
index 3f5b676..0435d65 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "CachedResourceClient.h"
 #include "Document.h"
+#include "FloatQuad.h"
 #include "RenderStyle.h"
 #include "ScrollTypes.h"
 #include "VisiblePosition.h"
@@ -561,7 +562,11 @@ public:
 
     // content area (box minus padding/border)
     IntRect contentBox() const;
+    // absolute coords of content area. Ignores transforms.
     IntRect absoluteContentBox() const;
+    // content rect converted to absolute coords, taking transforms into account
+    FloatQuad absoluteContentQuad() const;
+    
     int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); }
     int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); }
 
@@ -594,6 +599,9 @@ public:
         return localToAbsolute(localPoint, fixed, useTransforms);
     }
 
+    // Convert a local quad to an absolute quad, taking transforms into account.
+    virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
     // width and height are without margins but include paddings and borders
     virtual int width() const { return 0; }
     virtual int height() const { return 0; }
@@ -687,7 +695,12 @@ public:
     virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
 
     virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
-    IntRect absoluteBoundingBoxRect();
+    // FIXME: useTransforms should go away eventually
+    IntRect absoluteBoundingBoxRect(bool useTransforms = false);
+
+    // Build an array of quads in absolute coords for line boxes
+    virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
 
     // the rect that will be painted if this object is passed as the paintingRoot
     IntRect paintingRootRect(IntRect& topLevelRect);
index e825f76..fa83608 100644 (file)
@@ -239,6 +239,11 @@ void RenderPath::absoluteRects(Vector<IntRect>& rects, int, int, bool)
     rects.append(absoluteClippedOverflowRect());
 }
 
+void RenderPath::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    quads.append(absoluteClippedOverflowRect());
+}
+
 bool RenderPath::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction)
 {
     // We only draw in the forground phase, so we only hit-test then.
index ab966e4..d34ca1c 100644 (file)
@@ -69,6 +69,7 @@ public:
     virtual void paint(PaintInfo&, int parentX, int parentY);
 
     virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
     virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
 
     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
index c9c3cac..a72cd12 100644 (file)
@@ -393,6 +393,11 @@ void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool)
     rects.append(absoluteClippedOverflowRect());
 }
 
+void RenderSVGContainer::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    quads.append(absoluteClippedOverflowRect());
+}
+
 FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const
 {
     FloatRect rect;
index 06751a3..a7daa8a 100644 (file)
@@ -78,6 +78,7 @@ public:
 
     virtual IntRect absoluteClippedOverflowRect();
     virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
     virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
 
     FloatRect relativeBBox(bool includeStroke = true) const;
index bc758e5..5ef7719 100644 (file)
@@ -86,6 +86,11 @@ void RenderSVGHiddenContainer::absoluteRects(Vector<IntRect>& rects, int, int, b
     // This subtree does not take up space or paint
 }
 
+void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    // This subtree does not take up space or paint
+}
+
 AffineTransform RenderSVGHiddenContainer::absoluteTransform() const
 {
     return AffineTransform();
index c428a79..ad690a8 100644 (file)
@@ -53,6 +53,7 @@ namespace WebCore {
         
         virtual IntRect absoluteClippedOverflowRect();
         virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+        virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
         
         virtual AffineTransform absoluteTransform() const;
         virtual AffineTransform localTransform() const;
index 345e79f..7c75416 100644 (file)
@@ -237,6 +237,7 @@ void RenderSVGImage::imageChanged(WrappedImagePtr image)
 
 void RenderSVGImage::calculateAbsoluteBounds()
 {
+    // FIXME: broken with CSS transforms
     FloatRect absoluteRect = absoluteTransform().mapRect(relativeBBox(true));
 
 #if ENABLE(SVG_FILTERS)
@@ -269,6 +270,11 @@ void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int, bool)
     rects.append(absoluteClippedOverflowRect());
 }
 
+void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    quads.append(FloatRect(absoluteClippedOverflowRect()));
+}
+
 }
 
 #endif // ENABLE(SVG)
index 4891306..9b7cd21 100644 (file)
@@ -45,6 +45,7 @@ namespace WebCore {
         virtual FloatRect relativeBBox(bool includeStroke = true) const;
         virtual IntRect absoluteClippedOverflowRect();
         virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+        virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
         virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
 
         virtual void imageChanged(WrappedImagePtr);
index 4ba458d..87a89b4 100644 (file)
@@ -58,6 +58,11 @@ void RenderSVGInlineText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
     rects.append(computeAbsoluteRectForRange(0, textLength()));
 }
 
+void RenderSVGInlineText::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    quads.append(FloatRect(computeAbsoluteRectForRange(0, textLength())));
+}
+
 IntRect RenderSVGInlineText::selectionRect(bool)
 {
     ASSERT(!needsLayout());
@@ -115,6 +120,7 @@ IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPo
 
     FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + absPos.x() - xPos() - htmlParentCtm.e()),
                         narrowPrecisionToFloat(rect.y() + absPos.y() - yPos() - htmlParentCtm.f()), rect.width(), rect.height());
+    // FIXME: broken with CSS transforms
     return enclosingIntRect(absoluteTransform().mapRect(fixedRect));
 }
 
index 786ba31..dc7e851 100644 (file)
@@ -34,7 +34,10 @@ class RenderSVGInlineText : public RenderText {
 public:
     RenderSVGInlineText(Node*, PassRefPtr<StringImpl>);
     virtual const char* renderName() const { return "RenderSVGInlineText"; }
+
     virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
     virtual bool requiresLayer() { return false; }
     virtual IntRect selectionRect(bool clipToVisibleContent = true);
     virtual bool isSVGText() const { return true; }
index 1c59450..531376d 100644 (file)
@@ -259,6 +259,12 @@ void RenderSVGRoot::absoluteRects(Vector<IntRect>& rects, int, int)
         current->absoluteRects(rects, 0, 0);
 }
 
+void RenderSVGRoot::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+        current->absoluteQuads(quads);
+}
+
 AffineTransform RenderSVGRoot::absoluteTransform() const
 {
     AffineTransform ctm = RenderContainer::absoluteTransform();
index 58359fd..9a7954f 100644 (file)
@@ -49,6 +49,7 @@ public:
     
     virtual IntRect absoluteClippedOverflowRect();
     virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
     virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
 
     virtual AffineTransform absoluteTransform() const;
index a8d6c57..eb1b07b 100644 (file)
@@ -52,10 +52,31 @@ void RenderSVGTSpan::absoluteRects(Vector<IntRect>& rects, int, int, bool)
  
     for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
         FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+        // FIXME: broken with CSS transforms
         rects.append(enclosingIntRect(absoluteTransform().mapRect(rect)));
     }
 }
 
+void RenderSVGTSpan::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    InlineRunBox* firstBox = firstLineBox();
+
+    SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0;
+    RenderObject* object = rootBox ? rootBox->object() : 0;
+
+    if (!object)
+        return;
+
+    int xRef = object->xPos() + xPos();
+    int yRef = object->yPos() + yPos();
+    for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
+        FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+        // FIXME: broken with CSS transforms
+        quads.append(absoluteTransform().mapRect(rect));
+    }
+}
+
 }
 
 #endif // ENABLE(SVG)
index cabf2ef..d34cd2f 100644 (file)
@@ -33,6 +33,7 @@ public:
     RenderSVGTSpan(Node*);
     virtual const char* renderName() const { return "RenderSVGTSpan"; }
     virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
 };
 }
 
index 42b3427..a013a67 100644 (file)
@@ -164,11 +164,37 @@ void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
         for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) {
             FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height());
             boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f()));
+            // FIXME: broken with CSS transforms
             rects.append(enclosingIntRect(absoluteTransform().mapRect(boxRect)));
         }
     }
 }
 
+void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    RenderSVGRoot* root = findSVGRootObject(parent());
+    if (!root)
+        return;
+
+    FloatPoint absPos = localToAbsolute();
+
+    AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform();
+    // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard
+    // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'.
+    for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
+        ASSERT(runBox->isInlineFlowBox());
+
+        InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
+        for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) {
+            FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height());
+            boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f()));
+            // FIXME: broken with CSS transforms
+            quads.append(absoluteTransform().mapRect(boxRect));
+        }
+    }
+}
+
 void RenderSVGText::paint(PaintInfo& paintInfo, int, int)
 {   
     RenderObject::PaintInfo pi(paintInfo);
index ceadc82..73064fe 100644 (file)
@@ -51,6 +51,8 @@ public:
     virtual void layout();
     
     virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
     virtual IntRect absoluteClippedOverflowRect();
     virtual FloatRect relativeBBox(bool includeStroke = true) const;
     
index 53aa937..d5d8fde 100644 (file)
@@ -92,10 +92,31 @@ void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int)
 
     for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
         FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+        // FIXME: broken with CSS transforms
         rects.append(enclosingIntRect(absoluteTransform().mapRect(rect)));
     }
 }
 
+void RenderSVGTextPath::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    InlineRunBox* firstBox = firstLineBox();
+
+    SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0;
+    RenderObject* object = rootBox ? rootBox->object() : 0;
+
+    if (!object)
+        return;
+
+    int xRef = object->xPos() + xPos();
+    int yRef = object->yPos() + yPos();
+
+    for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
+        FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+        // FIXME: broken with CSS transforms
+        quads.append(absoluteTransform().mapRect(rect));
+    }
+}
+
 }
 
 #endif // ENABLE(SVG)
index 2a66f65..4fd4cc3 100644 (file)
@@ -39,6 +39,7 @@ namespace WebCore {
 
         virtual const char* renderName() const { return "RenderSVGTextPath"; }
         virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
+        virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
 
     private:
         float m_startOffset;
index 02f562f..02e7729 100644 (file)
@@ -203,7 +203,7 @@ FloatPoint RenderTableCell::localToAbsolute(FloatPoint localPoint, bool fixed, b
         // Rows are in the same coordinate space, so don't add their offset in.
         localPoint.move(-parent()->xPos(), -parent()->yPos());
     }
-    return RenderBlock::localToAbsolute(localPoint, fixed, useTransforms);;
+    return RenderBlock::localToAbsolute(localPoint, fixed, useTransforms);
 }
 
 FloatPoint RenderTableCell::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
@@ -216,6 +216,16 @@ FloatPoint RenderTableCell::absoluteToLocal(FloatPoint containerPoint, bool fixe
     return localPoint;
 }
 
+FloatQuad RenderTableCell::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+    FloatQuad quad = localQuad;
+    if (parent()) {
+        // Rows are in the same coordinate space, so don't add their offset in.
+        quad.move(-parent()->xPos(), -parent()->yPos());
+    }
+    return RenderBlock::localToAbsoluteQuad(quad, fixed);
+}
+
 int RenderTableCell::baselinePosition(bool /*firstLine*/, bool /*isRootLineBox*/) const
 {
     // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of
index c3f7c45..20b7da7 100644 (file)
@@ -103,6 +103,7 @@ public:
     virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false);
     virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
     virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+    virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
 
     virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const;
 
index 0a99cf5..8d8794b 100644 (file)
@@ -241,6 +241,49 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne
     }
 }
 
+void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+        quads.append(localToAbsoluteQuad(FloatRect(box->xPos(), box->yPos(), box->width(), box->height())));
+}
+
+void RenderText::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight)
+{
+    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
+    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this 
+    // function to take ints causes various internal mismatches. But selectionRect takes ints, and 
+    // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but 
+    // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
+    ASSERT(end == UINT_MAX || end <= INT_MAX);
+    ASSERT(start <= INT_MAX);
+    start = min(start, static_cast<unsigned>(INT_MAX));
+    end = min(end, static_cast<unsigned>(INT_MAX));
+    
+    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+        // Note: box->end() returns the index of the last character, not the index past it
+        if (start <= box->start() && box->end() < end) {
+            IntRect r = IntRect(box->xPos(), box->yPos(), box->width(), box->height());
+            if (useSelectionHeight) {
+                IntRect selectionRect = box->selectionRect(0, 0, start, end);
+                r.setHeight(selectionRect.height());
+                r.setY(selectionRect.y());
+            }
+            quads.append(localToAbsoluteQuad(FloatRect(r)));
+        } else {
+            unsigned realEnd = min(box->end() + 1, end);
+            IntRect r = box->selectionRect(0, 0, start, realEnd);
+            if (!r.isEmpty()) {
+                if (!useSelectionHeight) {
+                    // change the height and y position because selectionRect uses selection-specific values
+                    r.setHeight(box->height());
+                    r.setY(box->yPos());
+                }
+                quads.append(localToAbsoluteQuad(FloatRect(r)));
+            }
+        }
+    }
+}
+
 InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
 {
     // The text runs point to parts of the RenderText's m_text
index a68ba57..08e1035 100644 (file)
@@ -64,6 +64,9 @@ public:
     virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
     virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
 
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+    virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+
     virtual VisiblePosition positionForCoordinates(int x, int y);
 
     const UChar* characters() const { return m_text->characters(); }
index ad225dd..2a35702 100644 (file)
@@ -147,6 +147,15 @@ FloatPoint RenderView::absoluteToLocal(FloatPoint containerPoint, bool fixed, bo
     return containerPoint;
 }
 
+FloatQuad RenderView::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+    FloatQuad quad = localQuad;
+    if (fixed && m_frameView)
+        quad += m_frameView->scrollOffset();
+
+    return quad;
+}
+
 void RenderView::paint(PaintInfo& paintInfo, int tx, int ty)
 {
     // If we ever require layout but receive a paint anyway, something has gone horribly wrong.
@@ -242,6 +251,11 @@ void RenderView::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool)
     rects.append(IntRect(tx, ty, m_layer->width(), m_layer->height()));
 }
 
+void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+    quads.append(FloatRect(0, 0, m_layer->width(), m_layer->height()));
+}
+
 RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset)
 {
     if (!object)
index db579b1..c69dea6 100644 (file)
@@ -46,6 +46,7 @@ public:
     virtual void calcPrefWidths();
     virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
     virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+    virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
     
     int docHeight() const;
     int docWidth() const;
@@ -81,6 +82,7 @@ public:
     int truncatedAt() const { return m_truncatedAt; }
 
     virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+    virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
 
     IntRect selectionRect(bool clipToVisibleContent = true) const;