Bug 85532 - [meta] Enable sub-pixel layout on all platforms
Summary: [meta] Enable sub-pixel layout on all platforms
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Layout and Rendering (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on: 60318 85555 85671 86665 89458 94792 102622 113199
Blocks:
  Show dependency treegraph
 
Reported: 2012-05-03 12:34 PDT by Levi Weintraub
Modified: 2013-03-25 07:33 PDT (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Levi Weintraub 2012-05-03 12:34:35 PDT
bug to track enabling the SUBPIXEL_LAYOUT feature flag on all platforms.
Comment 1 Nikolas Zimmermann 2012-06-12 04:52:36 PDT
What's the status of sub pixel support? Can you give us an update Levi?
Comment 2 Levi Weintraub 2012-06-12 10:05:06 PDT
(In reply to comment #1)
> What's the status of sub pixel support? Can you give us an update Levi?

Sure.

Sub-pixel support is in but defaulted to off, behind the ENABLE_SUBPIXEL_LAYOUT flag. Chromium has turned this feature on (you can try it in the Dev channel), and all other ports are encouraged to do so.

I plan to follow up with encouraging other ports on webkit-dev when we've promoted this functionality to Chromium's beta or stable channel as that'll mean a lot more eyes have verified this functionality.

Do you have any specific questions?
Comment 3 Levi Weintraub 2012-06-13 21:01:02 PDT
(In reply to comment #2)
> (In reply to comment #1)
> > What's the status of sub pixel support? Can you give us an update Levi?
> 
> Sure.
> 
> Sub-pixel support is in but defaulted to off, behind the ENABLE_SUBPIXEL_LAYOUT flag. Chromium has turned this feature on (you can try it in the Dev channel), and all other ports are encouraged to do so.
> 
> I plan to follow up with encouraging other ports on webkit-dev when we've promoted this functionality to Chromium's beta or stable channel as that'll mean a lot more eyes have verified this functionality.
> 
> Do you have any specific questions?

I'd love an update on plans for enabling it in the KDE project ;)
Comment 4 Nikolas Zimmermann 2012-06-14 03:45:01 PDT
(In reply to comment #2)
> (In reply to comment #1)
> > What's the status of sub pixel support? Can you give us an update Levi?
> 
> Sure.
> 
> Sub-pixel support is in but defaulted to off, behind the ENABLE_SUBPIXEL_LAYOUT flag. Chromium has turned this feature on (you can try it in the Dev channel), and all other ports are encouraged to do so.
Excellent, I'll try this on Mac for a while.
 
> I plan to follow up with encouraging other ports on webkit-dev when we've promoted this functionality to Chromium's beta or stable channel as that'll mean a lot more eyes have verified this functionality.
> 
> Do you have any specific questions?
Not really, if it can be enabled I'm happy -- we can remove SVG specific FloatPoint/FloatRects in several places, if we could use the frameRect/borderBoxRect for this as example. I'm working on it.
Comment 5 Allan Sandfeld Jensen 2012-06-21 02:25:45 PDT
For your information. I have been testing sub-pixel layout on the Qt platform (to ensure my work on rect-based hit-testing was compatible with sub-pixel types), and it works perfectly with no regression I have noticed.
Comment 6 Nikolas Zimmermann 2012-06-26 07:48:01 PDT
(In reply to comment #3)
> I'd love an update on plans for enabling it in the KDE project ;)
I'm not working on KDE stuff since half a decade btw, historical reasons for my bugzilla account :-)

Anyhow, I've experimented lots with SUBPIXEL_LAYOUT turned on, on Mac. You've done a great job, it's working as-expected for most parts.

I've ran into an issue with transforming an absolute positioned <div>, which is aligned on sub-pixel boundaries, like this:

<html>
<body>
<div style="-moz-transform: scale(100); -webkit-transform: scale(100); background-color: green; position: absolute; left: -0.5px; top: -0.5px; width: 1px; height: 1px;"></div>
</body>
</html>

If you run this in trunk, you won't see anything, unless you zoom in or out at least once.
I've nailed down the problem, but I'm yet unsure on how to fix it properly, so I'd like to share it with you to get your insight:
void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    LayoutPoint adjustedPaintOffset = paintOffset + location();

    PaintPhase phase = paintInfo.phase;

    // Check if we need to do anything at all.
    // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
    // paints the root's background.
    if (!isRoot()) {
        LayoutRect overflowBox = visualOverflowRect();
        flipForWritingMode(overflowBox);
        overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
        overflowBox.moveBy(adjustedPaintOffset);
        if (!overflowBox.intersects(paintInfo.rect))
            return;
    ....

Break on RenderBlock::paint(), at some point:
Breakpoint 1, WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2626
2626	    LayoutPoint adjustedPaintOffset = paintOffset + location();
(gdb) p showRenderTreeForThis()
RenderView 0x109124108                 	#document	0x10882a600
  RenderBlock 0x109125b78              	HTML	0x109120380
    RenderBody 0x1091266d8             	BODY	0x109125ca0
*     RenderBlock (positioned) 0x1091271e8	DIV	0x109126400 STYLE=-moz-transform: scale(100); -webkit-transform: scale(100); background-color: green; position: absolute; left: -0.5px; top: -0.5px; width: 1px; height: 1px;

is reached.

2638	        if (!overflowBox.intersects(paintInfo.rect))
(gdb) p overflowBox
$39 = {
  m_location = {
    m_x = {
      m_value = 0
    }, 
    m_y = {
      m_value = 0
    }
  }, 
  m_size = {
    m_width = {
      m_value = 60
    }, 
    m_height = {
      m_value = 60
    }
  }
}

p paintInfo.rect
$40 = {
  m_location = {
    m_x = 1, 
    m_y = 1
  }, 
  m_size = {
    m_width = 8, 
    m_height = 6
  }
}

0x000000010269d7af in WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2638
2638	        if (!overflowBox.intersects(paintInfo.rect))
Value returned is $41 = false

And here's the problem. The paintInfo.rect has a location of 1x1, and a size of 8x6.
So let's examine where the incorrect paintInfo.rect is coming from:

(gdb) bt
#0  0x000000010269d7af in WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2638
#1  0x000000010279d729 in WebCore::RenderLayer::paintLayerContents (this=0x1091272b8, rootLayer=0x1091272b8, context=0x7fff5fbfb4c0, parentPaintDirtyRect=@0x7fff5fbf9b10, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3149

Looking at frame #1:
#1  0x000000010279d729 in WebCore::RenderLayer::paintLayerContents (this=0x1091272b8, rootLayer=0x1091272b8, context=0x7fff5fbfb4c0, parentPaintDirtyRect=@0x7fff5fbf9b10, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3149
3147	            // Paint the background.
3148	            PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0);
3149	            renderer()->paint(paintInfo, paintOffset);

(gdb) p damageRect.rect()
$51 = (const LayoutRect &) @0x7fff5fbf9908: {
  m_location = {
    m_x = {
      m_value = 30
    }, 
    m_y = {
      m_value = 30
    }
  }, 
  m_size = {
    m_width = {
      m_value = 480
    }, 
    m_height = {
      m_value = 360
    }
  }
}

The pixelSnappedIntRect() produces the x/y=1, width=8, height=6 IntRect.

Some more background info:
The RenderLayer associated with the <div> has a transform, scale(100).
#3  0x000000010279c370 in WebCore::RenderLayer::paintLayer (this=0x1091272b8, rootLayer=0x1091244c8, context=0x7fff5fbfb4c0, paintDirtyRect=@0x7fff5fbfa2d0, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3006

3001	        {
3002	            GraphicsContextStateSaver stateSaver(*context);
3003	            context->concatCTM(transform.toAffineTransform());
3004	
3005	            // Now do a paint with the root layer shifted to be us.
3006	            paintLayerContentsAndReflection(this, context, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
3007	        }        
3008	
3009	        // Restore the clip.
3010	        if (parent())

(gdb) p transform
$56 = {
  m_matrix = {{100, 0, 0, 0}, {0, 100, 0, 0}, {0, 0, 1, 0}, {-50, -50, 0, 1}}
}

(gdb) p paintDirtyRect
$58 = (const LayoutRect &) @0x7fff5fbfa2d0: {
  m_location = {
    m_x = {
      m_value = 0
    }, 
    m_y = {
      m_value = 0
    }
  }, 
  m_size = {
    m_width = {
      m_value = 48000
    }, 
    m_height = {
      m_value = 36000
    }
  }
}

The mapping of the paintDirtyRect through the inverse of the transform, produces x/y=30 (aka. 0.5).
Now that we know the root of the problem, if you change left/top to 0.4999px, it'll show up as expected, as the paintInfo.rect is now at 0x0, as 0.4999px is pixel-snapped to 0, instead of 1.

I'm unsure on how to fix this properly: the intersection between the pixel-snapped paint info rect and the overflow box is lossy, as the overflow box is sub-pixel aware.

(gdb) p toRenderBox(renderer())->m_frameRect
$61 = {
  m_location = {
    m_x = {
      m_value = -30
    }, 
    m_y = {
      m_value = -30
    }
  }, 
  m_size = {
    m_width = {
      m_value = 60
    }, 
    m_height = {
      m_value = 60
    }
  }
}

As no overflow is involved in my example, visualOverflowRect() == borderBoxRect(), aka. LayoutRect(0, 0, m_frameRect->width(), m_frameRect->height()) (in this example).

Sorry for the long post, but I thought I'd give as much information as possible, so we can discuss this easier. Levi, any idea?
Comment 7 Philip Rogers 2012-07-04 11:06:49 PDT
(In reply to comment #6)
> (In reply to comment #3)
> > I'd love an update on plans for enabling it in the KDE project ;)
> I'm not working on KDE stuff since half a decade btw, historical reasons for my bugzilla account :-)
> 
> Anyhow, I've experimented lots with SUBPIXEL_LAYOUT turned on, on Mac. You've done a great job, it's working as-expected for most parts.
> 
> I've ran into an issue with transforming an absolute positioned <div>, which is aligned on sub-pixel boundaries, like this:
> 
> <html>
> <body>
> <div style="-moz-transform: scale(100); -webkit-transform: scale(100); background-color: green; position: absolute; left: -0.5px; top: -0.5px; width: 1px; height: 1px;"></div>
> </body>
> </html>
> 
> If you run this in trunk, you won't see anything, unless you zoom in or out at least once.
> I've nailed down the problem, but I'm yet unsure on how to fix it properly, so I'd like to share it with you to get your insight:
> void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
> {
>     LayoutPoint adjustedPaintOffset = paintOffset + location();
> 
>     PaintPhase phase = paintInfo.phase;
> 
>     // Check if we need to do anything at all.
>     // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
>     // paints the root's background.
>     if (!isRoot()) {
>         LayoutRect overflowBox = visualOverflowRect();
>         flipForWritingMode(overflowBox);
>         overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
>         overflowBox.moveBy(adjustedPaintOffset);
>         if (!overflowBox.intersects(paintInfo.rect))
>             return;
>     ....
> 
> Break on RenderBlock::paint(), at some point:
> Breakpoint 1, WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2626
> 2626        LayoutPoint adjustedPaintOffset = paintOffset + location();
> (gdb) p showRenderTreeForThis()
> RenderView 0x109124108                     #document    0x10882a600
>   RenderBlock 0x109125b78                  HTML    0x109120380
>     RenderBody 0x1091266d8                 BODY    0x109125ca0
> *     RenderBlock (positioned) 0x1091271e8    DIV    0x109126400 STYLE=-moz-transform: scale(100); -webkit-transform: scale(100); background-color: green; position: absolute; left: -0.5px; top: -0.5px; width: 1px; height: 1px;
> 
> is reached.
> 
> 2638            if (!overflowBox.intersects(paintInfo.rect))
> (gdb) p overflowBox
> $39 = {
>   m_location = {
>     m_x = {
>       m_value = 0
>     }, 
>     m_y = {
>       m_value = 0
>     }
>   }, 
>   m_size = {
>     m_width = {
>       m_value = 60
>     }, 
>     m_height = {
>       m_value = 60
>     }
>   }
> }
> 
> p paintInfo.rect
> $40 = {
>   m_location = {
>     m_x = 1, 
>     m_y = 1
>   }, 
>   m_size = {
>     m_width = 8, 
>     m_height = 6
>   }
> }
> 
> 0x000000010269d7af in WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2638
> 2638            if (!overflowBox.intersects(paintInfo.rect))
> Value returned is $41 = false
> 
> And here's the problem. The paintInfo.rect has a location of 1x1, and a size of 8x6.
> So let's examine where the incorrect paintInfo.rect is coming from:
> 
> (gdb) bt
> #0  0x000000010269d7af in WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2638
> #1  0x000000010279d729 in WebCore::RenderLayer::paintLayerContents (this=0x1091272b8, rootLayer=0x1091272b8, context=0x7fff5fbfb4c0, parentPaintDirtyRect=@0x7fff5fbf9b10, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3149
> 
> Looking at frame #1:
> #1  0x000000010279d729 in WebCore::RenderLayer::paintLayerContents (this=0x1091272b8, rootLayer=0x1091272b8, context=0x7fff5fbfb4c0, parentPaintDirtyRect=@0x7fff5fbf9b10, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3149
> 3147                // Paint the background.
> 3148                PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0);
> 3149                renderer()->paint(paintInfo, paintOffset);
> 
> (gdb) p damageRect.rect()
> $51 = (const LayoutRect &) @0x7fff5fbf9908: {
>   m_location = {
>     m_x = {
>       m_value = 30
>     }, 
>     m_y = {
>       m_value = 30
>     }
>   }, 
>   m_size = {
>     m_width = {
>       m_value = 480
>     }, 
>     m_height = {
>       m_value = 360
>     }
>   }
> }
> 
> The pixelSnappedIntRect() produces the x/y=1, width=8, height=6 IntRect.
> 
> Some more background info:
> The RenderLayer associated with the <div> has a transform, scale(100).
> #3  0x000000010279c370 in WebCore::RenderLayer::paintLayer (this=0x1091272b8, rootLayer=0x1091244c8, context=0x7fff5fbfb4c0, paintDirtyRect=@0x7fff5fbfa2d0, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3006
> 
> 3001            {
> 3002                GraphicsContextStateSaver stateSaver(*context);
> 3003                context->concatCTM(transform.toAffineTransform());
> 3004    
> 3005                // Now do a paint with the root layer shifted to be us.
> 3006                paintLayerContentsAndReflection(this, context, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
> 3007            }        
> 3008    
> 3009            // Restore the clip.
> 3010            if (parent())
> 
> (gdb) p transform
> $56 = {
>   m_matrix = {{100, 0, 0, 0}, {0, 100, 0, 0}, {0, 0, 1, 0}, {-50, -50, 0, 1}}
> }
> 
> (gdb) p paintDirtyRect
> $58 = (const LayoutRect &) @0x7fff5fbfa2d0: {
>   m_location = {
>     m_x = {
>       m_value = 0
>     }, 
>     m_y = {
>       m_value = 0
>     }
>   }, 
>   m_size = {
>     m_width = {
>       m_value = 48000
>     }, 
>     m_height = {
>       m_value = 36000
>     }
>   }
> }
> 
> The mapping of the paintDirtyRect through the inverse of the transform, produces x/y=30 (aka. 0.5).
> Now that we know the root of the problem, if you change left/top to 0.4999px, it'll show up as expected, as the paintInfo.rect is now at 0x0, as 0.4999px is pixel-snapped to 0, instead of 1.
> 
> I'm unsure on how to fix this properly: the intersection between the pixel-snapped paint info rect and the overflow box is lossy, as the overflow box is sub-pixel aware.
> 
> (gdb) p toRenderBox(renderer())->m_frameRect
> $61 = {
>   m_location = {
>     m_x = {
>       m_value = -30
>     }, 
>     m_y = {
>       m_value = -30
>     }
>   }, 
>   m_size = {
>     m_width = {
>       m_value = 60
>     }, 
>     m_height = {
>       m_value = 60
>     }
>   }
> }
> 
> As no overflow is involved in my example, visualOverflowRect() == borderBoxRect(), aka. LayoutRect(0, 0, m_frameRect->width(), m_frameRect->height()) (in this example).
> 
> Sorry for the long post, but I thought I'd give as much information as possible, so we can discuss this easier. Levi, any idea?


Levi, eae: ping? This is somewhat of a blocker for the SVG2.0 work.
Comment 8 Emil A Eklund 2012-07-04 12:19:28 PDT
I'll try to get to this later today or tomorrow, been a busy week. Sorry about the delay.
Comment 9 Levi Weintraub 2012-07-25 14:55:37 PDT
(In reply to comment #7)
> (In reply to comment #6)
> > (In reply to comment #3)
> > > I'd love an update on plans for enabling it in the KDE project ;)
> > I'm not working on KDE stuff since half a decade btw, historical reasons for my bugzilla account :-)
> > 
> > Anyhow, I've experimented lots with SUBPIXEL_LAYOUT turned on, on Mac. You've done a great job, it's working as-expected for most parts.
> > 
> > I've ran into an issue with transforming an absolute positioned <div>, which is aligned on sub-pixel boundaries, like this:
> > 
> > <html>
> > <body>
> > <div style="-moz-transform: scale(100); -webkit-transform: scale(100); background-color: green; position: absolute; left: -0.5px; top: -0.5px; width: 1px; height: 1px;"></div>
> > </body>
> > </html>
> > 
> > If you run this in trunk, you won't see anything, unless you zoom in or out at least once.
> > I've nailed down the problem, but I'm yet unsure on how to fix it properly, so I'd like to share it with you to get your insight:
> > void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
> > {
> >     LayoutPoint adjustedPaintOffset = paintOffset + location();
> > 
> >     PaintPhase phase = paintInfo.phase;
> > 
> >     // Check if we need to do anything at all.
> >     // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
> >     // paints the root's background.
> >     if (!isRoot()) {
> >         LayoutRect overflowBox = visualOverflowRect();
> >         flipForWritingMode(overflowBox);
> >         overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
> >         overflowBox.moveBy(adjustedPaintOffset);
> >         if (!overflowBox.intersects(paintInfo.rect))
> >             return;
> >     ....
> > 
> > Break on RenderBlock::paint(), at some point:
> > Breakpoint 1, WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2626
> > 2626        LayoutPoint adjustedPaintOffset = paintOffset + location();
> > (gdb) p showRenderTreeForThis()
> > RenderView 0x109124108                     #document    0x10882a600
> >   RenderBlock 0x109125b78                  HTML    0x109120380
> >     RenderBody 0x1091266d8                 BODY    0x109125ca0
> > *     RenderBlock (positioned) 0x1091271e8    DIV    0x109126400 STYLE=-moz-transform: scale(100); -webkit-transform: scale(100); background-color: green; position: absolute; left: -0.5px; top: -0.5px; width: 1px; height: 1px;
> > 
> > is reached.
> > 
> > 2638            if (!overflowBox.intersects(paintInfo.rect))
> > (gdb) p overflowBox
> > $39 = {
> >   m_location = {
> >     m_x = {
> >       m_value = 0
> >     }, 
> >     m_y = {
> >       m_value = 0
> >     }
> >   }, 
> >   m_size = {
> >     m_width = {
> >       m_value = 60
> >     }, 
> >     m_height = {
> >       m_value = 60
> >     }
> >   }
> > }
> > 
> > p paintInfo.rect
> > $40 = {
> >   m_location = {
> >     m_x = 1, 
> >     m_y = 1
> >   }, 
> >   m_size = {
> >     m_width = 8, 
> >     m_height = 6
> >   }
> > }
> > 
> > 0x000000010269d7af in WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2638
> > 2638            if (!overflowBox.intersects(paintInfo.rect))
> > Value returned is $41 = false
> > 
> > And here's the problem. The paintInfo.rect has a location of 1x1, and a size of 8x6.
> > So let's examine where the incorrect paintInfo.rect is coming from:
> > 
> > (gdb) bt
> > #0  0x000000010269d7af in WebCore::RenderBlock::paint (this=0x1091271e8, paintInfo=@0x7fff5fbf97a8, paintOffset=@0x7fff5fbf98d0) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderBlock.cpp:2638
> > #1  0x000000010279d729 in WebCore::RenderLayer::paintLayerContents (this=0x1091272b8, rootLayer=0x1091272b8, context=0x7fff5fbfb4c0, parentPaintDirtyRect=@0x7fff5fbf9b10, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3149
> > 
> > Looking at frame #1:
> > #1  0x000000010279d729 in WebCore::RenderLayer::paintLayerContents (this=0x1091272b8, rootLayer=0x1091272b8, context=0x7fff5fbfb4c0, parentPaintDirtyRect=@0x7fff5fbf9b10, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3149
> > 3147                // Paint the background.
> > 3148                PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0);
> > 3149                renderer()->paint(paintInfo, paintOffset);
> > 
> > (gdb) p damageRect.rect()
> > $51 = (const LayoutRect &) @0x7fff5fbf9908: {
> >   m_location = {
> >     m_x = {
> >       m_value = 30
> >     }, 
> >     m_y = {
> >       m_value = 30
> >     }
> >   }, 
> >   m_size = {
> >     m_width = {
> >       m_value = 480
> >     }, 
> >     m_height = {
> >       m_value = 360
> >     }
> >   }
> > }
> > 
> > The pixelSnappedIntRect() produces the x/y=1, width=8, height=6 IntRect.
> > 
> > Some more background info:
> > The RenderLayer associated with the <div> has a transform, scale(100).
> > #3  0x000000010279c370 in WebCore::RenderLayer::paintLayer (this=0x1091272b8, rootLayer=0x1091244c8, context=0x7fff5fbfb4c0, paintDirtyRect=@0x7fff5fbfa2d0, paintBehavior=0, paintingRoot=0x0, region=0x0, overlapTestRequests=0x7fff5fbfb1c0, paintFlags=480) at /Users/nzimmermann/Coding/WebKit/Source/WebCore/rendering/RenderLayer.cpp:3006
> > 
> > 3001            {
> > 3002                GraphicsContextStateSaver stateSaver(*context);
> > 3003                context->concatCTM(transform.toAffineTransform());
> > 3004    
> > 3005                // Now do a paint with the root layer shifted to be us.
> > 3006                paintLayerContentsAndReflection(this, context, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
> > 3007            }        
> > 3008    
> > 3009            // Restore the clip.
> > 3010            if (parent())
> > 
> > (gdb) p transform
> > $56 = {
> >   m_matrix = {{100, 0, 0, 0}, {0, 100, 0, 0}, {0, 0, 1, 0}, {-50, -50, 0, 1}}
> > }
> > 
> > (gdb) p paintDirtyRect
> > $58 = (const LayoutRect &) @0x7fff5fbfa2d0: {
> >   m_location = {
> >     m_x = {
> >       m_value = 0
> >     }, 
> >     m_y = {
> >       m_value = 0
> >     }
> >   }, 
> >   m_size = {
> >     m_width = {
> >       m_value = 48000
> >     }, 
> >     m_height = {
> >       m_value = 36000
> >     }
> >   }
> > }
> > 
> > The mapping of the paintDirtyRect through the inverse of the transform, produces x/y=30 (aka. 0.5).
> > Now that we know the root of the problem, if you change left/top to 0.4999px, it'll show up as expected, as the paintInfo.rect is now at 0x0, as 0.4999px is pixel-snapped to 0, instead of 1.
> > 
> > I'm unsure on how to fix this properly: the intersection between the pixel-snapped paint info rect and the overflow box is lossy, as the overflow box is sub-pixel aware.
> > 
> > (gdb) p toRenderBox(renderer())->m_frameRect
> > $61 = {
> >   m_location = {
> >     m_x = {
> >       m_value = -30
> >     }, 
> >     m_y = {
> >       m_value = -30
> >     }
> >   }, 
> >   m_size = {
> >     m_width = {
> >       m_value = 60
> >     }, 
> >     m_height = {
> >       m_value = 60
> >     }
> >   }
> > }
> > 
> > As no overflow is involved in my example, visualOverflowRect() == borderBoxRect(), aka. LayoutRect(0, 0, m_frameRect->width(), m_frameRect->height()) (in this example).
> > 
> > Sorry for the long post, but I thought I'd give as much information as possible, so we can discuss this easier. Levi, any idea?
> 
> 
> Levi, eae: ping? This is somewhat of a blocker for the SVG2.0 work.

Apologies for the slow response -- I've been away on vacation. This is yet another issue that is solved by the patch on https://bugs.webkit.org/show_bug.cgi?id=89238. I've been trying rather unsuccessfully to get a review (and have been out of town) if one of you have a chance to take a look.
Comment 10 Chris Drackett 2012-07-31 19:01:55 PDT
does this ticket cover adding subpixel support to "normal" css properties (border-size, box-shadow, margin, etc.)
Comment 11 Emil A Eklund 2012-08-01 16:11:52 PDT
(In reply to comment #10)
> does this ticket cover adding subpixel support to "normal" css properties (border-size, box-shadow, margin, etc.)

This bug is about enabling the subpixel support for platforms other than chromium.
See https://trac.webkit.org/wiki/LayoutUnit for details about what that entails.
Comment 12 Nikolas Zimmermann 2012-08-22 06:40:25 PDT
(In reply to comment #9)
> Apologies for the slow response -- I've been away on vacation. This is yet another issue that is solved by the patch on https://bugs.webkit.org/show_bug.cgi?id=89238. I've been trying rather unsuccessfully to get a review (and have been out of town) if one of you have a chance to take a look.
Oh, does that mean it's fixed now? Going to retry w/o my workarounds then.
Comment 13 Levi Weintraub 2012-08-22 07:37:37 PDT
(In reply to comment #12)
> Oh, does that mean it's fixed now? Going to retry w/o my workarounds then.

Let me know if there continues to be an issue.