https://bugs.webkit.org/show_bug.cgi?id=78040
Reviewed by Eric Seidel.
Add pixel snapped versions of x/y/width/height methods. These return the
same value as the x/w/width/height methods for now but once we move over
to sub pixel layout they will snap the subpixel value to a device pixel
and return an integer value.
When snapping the left and top edge is simply rounded to the nearest
device pixel.
The right and bottom edges are computed by subtracting the rounded left/
top edge from the precise location and size. This ensures that the edges
all line up with device pixels and that the total size of an object,
including borders, is at most one pixel off.
In summary, the values are computed as follows:
x: round(x)
y: round(y)
maxX: round(x + width)
maxY: round(y + height)
width: round(x + width) - round(x)
height: round(y + height) - round(y)
We use the term pixel snapped to indicate that the numbers are not merely
rounded. This also matches the naming used by the line box tree.
No new tests, no functionality changes.
* page/PrintContext.cpp:
(WebCore::PrintContext::pageNumberForElement):
* rendering/RenderBlock.cpp:
(WebCore::::collectIfNeeded):
* rendering/RenderBlock.h:
(RenderBlock):
(WebCore::RenderBlock::pixelSnappedLogicalRightOffsetForLine):
(WebCore::RenderBlock::pixelSnappedLogicalLeftOffsetForLine):
(WebCore::RenderBlock::FloatingObject::pixelSnappedX):
(WebCore::RenderBlock::FloatingObject::pixelSnappedMaxX):
(WebCore::RenderBlock::FloatingObject::pixelSnappedY):
(WebCore::RenderBlock::FloatingObject::pixelSnappedMaxY):
(WebCore::RenderBlock::FloatingObject::pixelSnappedWidth):
(WebCore::RenderBlock::FloatingObject::pixelSnappedHeight):
(FloatingObject):
(WebCore::RenderBlock::pixelSnappedLogicalTopForFloat):
(WebCore::RenderBlock::pixelSnappedLogicalBottomForFloat):
(WebCore::RenderBlock::pixelSnappedLogicalLeftForFloat):
(WebCore::RenderBlock::pixelSnappedLogicalRightForFloat):
* rendering/RenderBlockLineLayout.cpp:
(WebCore::LineWidth::shrinkAvailableWidthForNewFloatIfNeeded):
* rendering/RenderBox.cpp:
(WebCore::RenderBox::pixelSnappedClientWidth):
(WebCore):
(WebCore::RenderBox::pixelSnappedClientHeight):
(WebCore::RenderBox::scrollHeight):
* rendering/RenderBox.h:
(WebCore::RenderBox::pixelSnappedWidth):
(WebCore::RenderBox::pixelSnappedHeight):
(RenderBox):
(WebCore::RenderBox::pixelSnappedOffsetWidth):
(WebCore::RenderBox::pixelSnappedOffsetHeight):
(WebCore::RenderBox::clientLogicalWidth):
(WebCore::RenderBox::clientLogicalHeight):
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::pixelSnappedOffsetWidth):
(WebCore):
(WebCore::RenderBoxModelObject::pixelSnappedOffsetHeight):
* rendering/RenderBoxModelObject.h:
(WebCore::RenderBoxModelObject::pixelSnappedOffsetLeft):
(WebCore::RenderBoxModelObject::pixelSnappedOffsetTop):
(RenderBoxModelObject):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::pixelSnappedScrollWidth):
(WebCore):
(WebCore::RenderLayer::pixelSnappedScrollHeight):
(WebCore::RenderLayer::computeScrollDimensions):
(WebCore::RenderLayer::updateScrollInfoAfterLayout):
* rendering/RenderLayer.h:
(RenderLayer):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::scrollHeight):
* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::volumeSliderOffsetFromMuteButton):
* rendering/RenderTreeAsText.cpp:
(WebCore::write):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@107032
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-02-07 Emil A Eklund <eae@chromium.org>
+
+ Add pixelSnappedX/Y/Width/Height methods
+ https://bugs.webkit.org/show_bug.cgi?id=78040
+
+ Reviewed by Eric Seidel.
+
+ Add pixel snapped versions of x/y/width/height methods. These return the
+ same value as the x/w/width/height methods for now but once we move over
+ to sub pixel layout they will snap the subpixel value to a device pixel
+ and return an integer value.
+
+ When snapping the left and top edge is simply rounded to the nearest
+ device pixel.
+ The right and bottom edges are computed by subtracting the rounded left/
+ top edge from the precise location and size. This ensures that the edges
+ all line up with device pixels and that the total size of an object,
+ including borders, is at most one pixel off.
+
+ In summary, the values are computed as follows:
+ x: round(x)
+ y: round(y)
+ maxX: round(x + width)
+ maxY: round(y + height)
+ width: round(x + width) - round(x)
+ height: round(y + height) - round(y)
+
+ We use the term pixel snapped to indicate that the numbers are not merely
+ rounded. This also matches the naming used by the line box tree.
+
+ No new tests, no functionality changes.
+
+ * page/PrintContext.cpp:
+ (WebCore::PrintContext::pageNumberForElement):
+ * rendering/RenderBlock.cpp:
+ (WebCore::::collectIfNeeded):
+ * rendering/RenderBlock.h:
+ (RenderBlock):
+ (WebCore::RenderBlock::pixelSnappedLogicalRightOffsetForLine):
+ (WebCore::RenderBlock::pixelSnappedLogicalLeftOffsetForLine):
+ (WebCore::RenderBlock::FloatingObject::pixelSnappedX):
+ (WebCore::RenderBlock::FloatingObject::pixelSnappedMaxX):
+ (WebCore::RenderBlock::FloatingObject::pixelSnappedY):
+ (WebCore::RenderBlock::FloatingObject::pixelSnappedMaxY):
+ (WebCore::RenderBlock::FloatingObject::pixelSnappedWidth):
+ (WebCore::RenderBlock::FloatingObject::pixelSnappedHeight):
+ (FloatingObject):
+ (WebCore::RenderBlock::pixelSnappedLogicalTopForFloat):
+ (WebCore::RenderBlock::pixelSnappedLogicalBottomForFloat):
+ (WebCore::RenderBlock::pixelSnappedLogicalLeftForFloat):
+ (WebCore::RenderBlock::pixelSnappedLogicalRightForFloat):
+ * rendering/RenderBlockLineLayout.cpp:
+ (WebCore::LineWidth::shrinkAvailableWidthForNewFloatIfNeeded):
+ * rendering/RenderBox.cpp:
+ (WebCore::RenderBox::pixelSnappedClientWidth):
+ (WebCore):
+ (WebCore::RenderBox::pixelSnappedClientHeight):
+ (WebCore::RenderBox::scrollHeight):
+ * rendering/RenderBox.h:
+ (WebCore::RenderBox::pixelSnappedWidth):
+ (WebCore::RenderBox::pixelSnappedHeight):
+ (RenderBox):
+ (WebCore::RenderBox::pixelSnappedOffsetWidth):
+ (WebCore::RenderBox::pixelSnappedOffsetHeight):
+ (WebCore::RenderBox::clientLogicalWidth):
+ (WebCore::RenderBox::clientLogicalHeight):
+ * rendering/RenderBoxModelObject.cpp:
+ (WebCore::RenderBoxModelObject::pixelSnappedOffsetWidth):
+ (WebCore):
+ (WebCore::RenderBoxModelObject::pixelSnappedOffsetHeight):
+ * rendering/RenderBoxModelObject.h:
+ (WebCore::RenderBoxModelObject::pixelSnappedOffsetLeft):
+ (WebCore::RenderBoxModelObject::pixelSnappedOffsetTop):
+ (RenderBoxModelObject):
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::pixelSnappedScrollWidth):
+ (WebCore):
+ (WebCore::RenderLayer::pixelSnappedScrollHeight):
+ (WebCore::RenderLayer::computeScrollDimensions):
+ (WebCore::RenderLayer::updateScrollInfoAfterLayout):
+ * rendering/RenderLayer.h:
+ (RenderLayer):
+ * rendering/RenderListBox.cpp:
+ (WebCore::RenderListBox::scrollHeight):
+ * rendering/RenderTheme.cpp:
+ (WebCore::RenderTheme::volumeSliderOffsetFromMuteButton):
+ * rendering/RenderTreeAsText.cpp:
+ (WebCore::write):
+
2012-02-07 Mike Lawther <mikelawther@chromium.org>
CSS3 calc() - simple parse time evaluation
scaledPageSize.scale(frame->view()->contentsSize().width() / pageRect.width());
printContext.computePageRectsWithPageSize(scaledPageSize, false);
- int top = box->offsetTop();
- int left = box->offsetLeft();
+ int top = box->pixelSnappedOffsetTop();
+ int left = box->pixelSnappedOffsetLeft();
size_t pageNumber = 0;
for (; pageNumber < printContext.pageCount(); pageNumber++) {
const IntRect& page = printContext.pageRect(pageNumber);
const FloatingObject* r = interval.data();
if (r->type() == FloatTypeValue && interval.low() <= m_value && m_value < interval.high()) {
// All the objects returned from the tree should be already placed.
- ASSERT(r->isPlaced() && m_renderer->logicalTopForFloat(r) <= m_value && m_renderer->logicalBottomForFloat(r) > m_value);
+ ASSERT(r->isPlaced() && m_renderer->pixelSnappedLogicalTopForFloat(r) <= m_value && m_renderer->pixelSnappedLogicalBottomForFloat(r) > m_value);
if (FloatTypeValue == FloatingObject::FloatLeft
&& m_renderer->logicalRightForFloat(r) > m_offset) {
return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine)
: logicalWidth() - logicalRightOffsetForLine(position, firstLine);
}
+
+ // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
+ int pixelSnappedLogicalRightOffsetForLine(LayoutUnit position, bool firstLine) const
+ {
+ return logicalRightOffsetForLine(position, logicalRightOffsetForContent(position), firstLine, 0);
+ }
+
+ int pixelSnappedLogicalLeftOffsetForLine(LayoutUnit position, bool firstLine) const
+ {
+ return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(position), firstLine, 0);
+ }
LayoutUnit startAlignedOffsetForLine(RenderBox* child, LayoutUnit position, bool firstLine);
LayoutUnit textIndentOffset() const;
LayoutUnit width() const { return m_frameRect.width(); }
LayoutUnit height() const { return m_frameRect.height(); }
+ // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
+ int pixelSnappedX() const { return x(); }
+ int pixelSnappedMaxX() const { return maxX(); }
+ int pixelSnappedY() const { return y(); }
+ int pixelSnappedMaxY() const { return maxY(); }
+ int pixelSnappedWidth() const { return width(); }
+ int pixelSnappedHeight() const { return height(); }
+
void setX(LayoutUnit x) { ASSERT(!isInPlacedTree()); m_frameRect.setX(x); }
void setY(LayoutUnit y) { ASSERT(!isInPlacedTree()); m_frameRect.setY(y); }
void setWidth(LayoutUnit width) { ASSERT(!isInPlacedTree()); m_frameRect.setWidth(width); }
LayoutUnit logicalRightForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->maxX() : child->maxY(); }
LayoutUnit logicalWidthForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->width() : child->height(); }
+ // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
+ int pixelSnappedLogicalTopForFloat(const FloatingObject* child) const { return logicalTopForFloat(child); }
+ int pixelSnappedLogicalBottomForFloat(const FloatingObject* child) const { return logicalBottomForFloat(child); }
+ int pixelSnappedLogicalLeftForFloat(const FloatingObject* child) const { return logicalLeftForFloat(child); }
+ int pixelSnappedLogicalRightForFloat(const FloatingObject* child) const { return logicalRightForFloat(child); }
+
void setLogicalTopForFloat(FloatingObject* child, LayoutUnit logicalTop)
{
if (isHorizontalWritingMode())
return;
if (newFloat->type() == RenderBlock::FloatingObject::FloatLeft) {
- m_left = m_block->logicalRightForFloat(newFloat);
+ m_left = m_block->pixelSnappedLogicalRightForFloat(newFloat);
if (m_isFirstLine && m_block->style()->isLeftToRightDirection())
m_left += m_block->textIndentOffset();
} else {
- m_right = m_block->logicalLeftForFloat(newFloat);
+ m_right = m_block->pixelSnappedLogicalLeftForFloat(newFloat);
if (m_isFirstLine && !m_block->style()->isLeftToRightDirection())
m_right -= m_block->textIndentOffset();
}
return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
}
+int RenderBox::pixelSnappedClientWidth() const
+{
+ return clientWidth();
+}
+
+int RenderBox::pixelSnappedClientHeight() const
+{
+ return clientHeight();
+}
+
int RenderBox::scrollWidth() const
{
if (hasOverflowClip())
return layer()->scrollHeight();
// For objects with visible overflow, this matches IE.
// FIXME: Need to work right with writing modes.
- return max(clientHeight(), maxYLayoutOverflow() - borderTop());
+ return max(pixelSnappedClientHeight(), maxYLayoutOverflow() - borderTop());
}
int RenderBox::scrollLeft() const
LayoutUnit width() const { return m_frameRect.width(); }
LayoutUnit height() const { return m_frameRect.height(); }
+ // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
+ int pixelSnappedWidth() const { return m_frameRect.width(); }
+ int pixelSnappedHeight() const { return m_frameRect.height(); }
+
// These represent your location relative to your container as a physical offset.
// In layout related methods you almost always want the logical location (e.g. x() and y()).
LayoutUnit top() const { return topLeftLocation().y(); }
virtual LayoutUnit offsetWidth() const { return width(); }
virtual LayoutUnit offsetHeight() const { return height(); }
+ // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
+ virtual int pixelSnappedOffsetWidth() const { return pixelSnappedWidth(); }
+ virtual int pixelSnappedOffsetHeight() const { return pixelSnappedHeight(); }
+
// More IE extensions. clientWidth and clientHeight represent the interior of an object
// excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth.
LayoutUnit clientLeft() const { return borderLeft(); }
LayoutUnit clientTop() const { return borderTop(); }
LayoutUnit clientWidth() const;
LayoutUnit clientHeight() const;
- LayoutUnit clientLogicalWidth() const { return style()->isHorizontalWritingMode() ? clientWidth() : clientHeight(); }
- LayoutUnit clientLogicalHeight() const { return style()->isHorizontalWritingMode() ? clientHeight() : clientWidth(); }
+ LayoutUnit clientLogicalWidth() const { return style()->isHorizontalWritingMode() ? pixelSnappedClientWidth() : pixelSnappedClientHeight(); }
+ LayoutUnit clientLogicalHeight() const { return style()->isHorizontalWritingMode() ? pixelSnappedClientHeight() : pixelSnappedClientWidth(); }
LayoutUnit clientLogicalBottom() const { return borderBefore() + clientLogicalHeight(); }
LayoutRect clientBoxRect() const { return LayoutRect(clientLeft(), clientTop(), clientWidth(), clientHeight()); }
+ int pixelSnappedClientWidth() const;
+ int pixelSnappedClientHeight() const;
+
// scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
// object has overflow:hidden/scroll/auto specified and also has overflow.
// scrollLeft/Top return the current scroll position. These methods are virtual so that objects like
return yPos;
}
+int RenderBoxModelObject::pixelSnappedOffsetWidth() const
+{
+ return offsetWidth();
+}
+
+int RenderBoxModelObject::pixelSnappedOffsetHeight() const
+{
+ return offsetHeight();
+}
+
LayoutUnit RenderBoxModelObject::paddingTop(bool) const
{
LayoutUnit w = 0;
virtual LayoutUnit offsetWidth() const = 0;
virtual LayoutUnit offsetHeight() const = 0;
+ // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318.
+ int pixelSnappedOffsetLeft() const { return offsetLeft(); }
+ int pixelSnappedOffsetTop() const { return offsetTop(); }
+ int pixelSnappedOffsetWidth() const;
+ int pixelSnappedOffsetHeight() const;
+
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
virtual void updateBoxModelInfoFromStyle();
return m_scrollSize.height();
}
+int RenderLayer::pixelSnappedScrollWidth()
+{
+ return scrollWidth();
+}
+
+int RenderLayer::pixelSnappedScrollHeight()
+{
+ return scrollHeight();
+}
+
LayoutUnit RenderLayer::overflowTop() const
{
RenderBox* box = renderBox();
setScrollOrigin(IntPoint(-m_scrollOverflow.width(), -m_scrollOverflow.height()));
if (needHBar)
- *needHBar = m_scrollSize.width() > box->clientWidth();
+ *needHBar = pixelSnappedScrollWidth() > box->pixelSnappedClientWidth();
if (needVBar)
- *needVBar = m_scrollSize.height() > box->clientHeight();
+ *needVBar = pixelSnappedScrollHeight() > box->pixelSnappedClientHeight();
}
void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
// Set up the range (and page step/line step).
if (m_hBar) {
- LayoutUnit clientWidth = box->clientWidth();
- LayoutUnit pageStep = max<LayoutUnit>(max<LayoutUnit>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
+ int clientWidth = box->pixelSnappedClientWidth();
+ int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_hBar->setProportion(clientWidth, m_scrollSize.width());
}
if (m_vBar) {
- LayoutUnit clientHeight = box->clientHeight();
- LayoutUnit pageStep = max<LayoutUnit>(max<LayoutUnit>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
+ int clientHeight = box->pixelSnappedClientHeight();
+ int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_vBar->setProportion(clientHeight, m_scrollSize.height());
}
LayoutUnit scrollWidth();
LayoutUnit scrollHeight();
+ int pixelSnappedScrollWidth();
+ int pixelSnappedScrollHeight();
void panScrollFromPoint(const LayoutPoint&);
int RenderListBox::scrollHeight() const
{
- return max(clientHeight(), listHeight());
+ return max(pixelSnappedClientHeight(), listHeight());
}
int RenderListBox::scrollLeft() const
LayoutPoint RenderTheme::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const LayoutSize& size) const
{
LayoutUnit y = -size.height();
- FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->offsetLeft(), y), true, true);
+ FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), true, true);
if (absPoint.y() < 0)
y = muteButtonBox->height();
return LayoutPoint(0, y);
ts << " scrollX " << l.scrollXOffset();
if (l.scrollYOffset())
ts << " scrollY " << l.scrollYOffset();
- if (l.renderBox() && l.renderBox()->clientWidth() != l.scrollWidth())
- ts << " scrollWidth " << l.scrollWidth();
- if (l.renderBox() && l.renderBox()->clientHeight() != l.scrollHeight())
- ts << " scrollHeight " << l.scrollHeight();
+ if (l.renderBox() && l.renderBox()->pixelSnappedClientWidth() != l.pixelSnappedScrollWidth())
+ ts << " scrollWidth " << l.pixelSnappedScrollWidth();
+ if (l.renderBox() && l.renderBox()->pixelSnappedClientHeight() != l.pixelSnappedScrollHeight())
+ ts << " scrollHeight " << l.pixelSnappedScrollHeight();
}
if (paintPhase == LayerPaintPhaseBackground)