提交 41c3e58e 编写于 作者: H Hixie

Use the baseline information exposed by C++ to pipe baseline data through RenderBox.

This also fixes the C++ side to give the right baseline information.
Previously it was giving the baseline distance for the font, but not
for the actual laid-out text.

I considered also providing a "defaultBaseline" accessor that returns
the distance for the actual dominant baseline, but it turns out right
now we never decide the baseline is ideographic. We always use the
alphabetic baseline. We should probably fix that...

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/1200233002.
上级 29ae65d2
......@@ -975,14 +975,14 @@ void Element::setMaxContentWidth(double width)
double Element::alphabeticBaseline() const
{
if (RenderBox* box = renderBox())
return box->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOfInteriorLineBoxes);
return box->firstLineBoxBaseline(FontBaselineOrAuto(AlphabeticBaseline));
return 0;
}
double Element::ideographicBaseline() const
{
if (RenderBox* box = renderBox())
return box->baselinePosition(IdeographicBaseline, true, HorizontalLine, PositionOfInteriorLineBoxes);
return box->firstLineBoxBaseline(FontBaselineOrAuto(IdeographicBaseline));
return 0;
}
......
......@@ -1351,11 +1351,11 @@ LayoutUnit RenderBlock::minLineHeightForReplacedRenderer(bool isFirstLine, Layou
return std::max<LayoutUnit>(replacedHeight, lineHeight(isFirstLine, HorizontalLine, PositionOfInteriorLineBoxes));
}
int RenderBlock::firstLineBoxBaseline() const
int RenderBlock::firstLineBoxBaseline(FontBaselineOrAuto baselineType) const
{
for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
if (!curr->isFloatingOrOutOfFlowPositioned()) {
int result = curr->firstLineBoxBaseline();
int result = curr->firstLineBoxBaseline(baselineType);
if (result != -1)
return curr->logicalTop() + result; // Translate to our coordinate space.
}
......
......@@ -216,7 +216,7 @@ protected:
virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override;
virtual void computePreferredLogicalWidths() override;
virtual int firstLineBoxBaseline() const override;
virtual int firstLineBoxBaseline(FontBaselineOrAuto baselineType) const override;
virtual int inlineBlockBaseline(LineDirectionMode) const override;
virtual int lastLineBoxBaseline(LineDirectionMode) const;
......
......@@ -66,6 +66,21 @@ enum LayerType {
OverflowClipLayer,
};
struct FontBaselineOrAuto {
FontBaselineOrAuto()
: m_auto(true)
, m_baseline(AlphabeticBaseline)
{
}
FontBaselineOrAuto(FontBaseline baseline)
: m_auto(false)
, m_baseline(baseline)
{
}
bool m_auto;
FontBaseline m_baseline;
};
class RenderBox : public RenderBoxModelObject {
public:
explicit RenderBox(ContainerNode*);
......@@ -429,7 +444,7 @@ public:
RenderLayer* enclosingFloatPaintingLayer() const;
virtual int firstLineBoxBaseline() const { return -1; }
virtual int firstLineBoxBaseline(FontBaselineOrAuto baselineType) const { return -1; }
virtual int inlineBlockBaseline(LineDirectionMode) const { return -1; } // Returns -1 if we should skip this box when computing the baseline of an inline-block.
bool isFlexItem() const { return !isInline() && !isFloatingOrOutOfFlowPositioned() && parent() && parent()->isFlexibleBox(); }
......
......@@ -119,14 +119,14 @@ static int synthesizedBaselineFromContentBox(const RenderBox* box, LineDirection
int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
{
ASSERT(mode == PositionOnContainingLine);
int baseline = firstLineBoxBaseline();
int baseline = firstLineBoxBaseline(FontBaselineOrAuto());
if (baseline == -1)
baseline = synthesizedBaselineFromContentBox(this, direction);
return beforeMarginInLineDirection(direction) + baseline;
}
int RenderFlexibleBox::firstLineBoxBaseline() const
int RenderFlexibleBox::firstLineBoxBaseline(FontBaselineOrAuto baselineType) const
{
if (m_numberOfInFlowChildrenOnFirstLine <= 0)
return -1;
......@@ -155,7 +155,7 @@ int RenderFlexibleBox::firstLineBoxBaseline() const
if (isColumnFlow() && !hasOrthogonalFlow(baselineChild))
return mainAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
int baseline = baselineChild->firstLineBoxBaseline();
int baseline = baselineChild->firstLineBoxBaseline(baselineType);
if (baseline == -1) {
// FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
// This would also fix some cases where the flexbox is orthogonal to its container.
......@@ -168,7 +168,7 @@ int RenderFlexibleBox::firstLineBoxBaseline() const
int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
{
int baseline = firstLineBoxBaseline();
int baseline = firstLineBoxBaseline(FontBaselineOrAuto());
if (baseline != -1)
return baseline;
......@@ -680,7 +680,7 @@ bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUni
LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
{
LayoutUnit ascent = child->firstLineBoxBaseline();
LayoutUnit ascent = child->firstLineBoxBaseline(FontBaselineOrAuto());
if (ascent == -1)
ascent = crossAxisExtentForChild(child);
return ascent + flowAwareMarginBeforeForChild(child);
......
......@@ -47,7 +47,7 @@ public:
void layout();
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const override;
virtual int firstLineBoxBaseline() const override;
virtual int firstLineBoxBaseline(FontBaselineOrAuto baselineType) const override;
virtual int inlineBlockBaseline(LineDirectionMode) const override;
virtual void paintChildren(PaintInfo&, const LayoutPoint&, Vector<RenderBox*>& layers) override final;
......
......@@ -1356,9 +1356,16 @@ void RenderParagraph::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth,
maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
}
int RenderParagraph::firstLineBoxBaseline() const
int RenderParagraph::firstLineBoxBaseline(FontBaselineOrAuto baselineType) const
{
return firstLineBox() ? firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType()) : -1;
if (!firstLineBox())
return -1;
FontBaseline baseline;
if (baselineType.m_auto)
baseline = firstRootBox()->baselineType();
else
baseline = baselineType.m_baseline;
return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(baseline);
}
int RenderParagraph::lastLineBoxBaseline(LineDirectionMode lineDirection) const
......
......@@ -74,7 +74,7 @@ protected:
void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const final;
int firstLineBoxBaseline() const final;
int firstLineBoxBaseline(FontBaselineOrAuto baselineType) const final;
int lastLineBoxBaseline(LineDirectionMode) const final;
private:
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
RenderBox getBox(double lh) {
RenderParagraph paragraph = new RenderParagraph(
new InlineStyle(
new TextStyle(),
[
new InlineText('test'),
new InlineStyle(
new TextStyle(
color: const Color(0xFF0000A0),
fontFamily: 'serif',
fontSize: 50.0,
height: lh
),
[new InlineText('مرحبا Hello')]
)
]
)
);
return new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 200.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
backgroundColor: const Color(0xFFFFFFFF)
),
child: new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderCustomPaint(
child: paragraph,
callback: (canvas, size) {
double baseline = paragraph.getDistanceToBaseline(TextBaseline.alphabetic);
double w = paragraph.getMaxIntrinsicWidth(new BoxConstraints.loose(size));
double h = paragraph.getMaxIntrinsicHeight(new BoxConstraints.loose(size));
Path path = new Path();
path.moveTo(0.0, 0.0);
path.lineTo(w, 0.0);
path.moveTo(0.0, baseline);
path.lineTo(w, baseline);
path.moveTo(0.0, h);
path.lineTo(w, h);
Paint paint = new Paint();
paint.color = const Color(0xFFFF9000);
paint.setStyle(sky.PaintingStyle.stroke);
paint.strokeWidth = 3.0;
canvas.drawPath(path, paint);
}
)
)
)
)
);
}
void main() {
RenderBox root = new RenderBlock(children: [
new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 50.0)
),
getBox(1.0),
getBox(null),
]);
var b = new SkyBinding(root: root);
// b.onFrame = b.debugDumpRenderTree;
}
......@@ -77,6 +77,10 @@ class RenderBlock extends RenderBox with ContainerRenderObjectMixin<RenderBox, B
return _getIntrinsicHeight(constraints);
}
double getDistanceToActualBaseline(TextBaseline baseline) {
return defaultGetDistanceToFirstActualBaseline(baseline);
}
void performLayout() {
assert(constraints is BoxConstraints);
double width = constraints.constrainWidth(constraints.maxWidth);
......
......@@ -225,6 +225,8 @@ class BoxParentData extends ParentData {
String toString() => 'position=$position';
}
enum TextBaseline { alphabetic, ideographic }
abstract class RenderBox extends RenderObject {
void setParentData(RenderObject child) {
......@@ -259,6 +261,31 @@ abstract class RenderBox extends RenderObject {
return constraints.constrainHeight(0.0);
}
// getDistanceToBaseline() should return the distance from the
// y-coordinate of the position of the box to the y-coordinate of
// the first given baseline in the box's contents. This is used by
// certain layout models to align adjacent boxes on a common
// baseline, regardless of padding, font size differences, etc. If
// there is no baseline, then it should return the distance from the
// y-coordinate of the position of the box to the y-coordinate of
// the bottom of the box, i.e., the height of the box.
// Only call this after layout has been performed.
double getDistanceToBaseline(TextBaseline baseline) {
assert(!needsLayout);
double result = getDistanceToActualBaseline(baseline);
if (result == null)
return size.height;
return result;
}
// getDistanceToActualBaseline() should return the distance from the
// y-coordinate of the position of the box to the y-coordinate of
// the first given baseline in the box's contents, if any, or null
// otherwise.
double getDistanceToActualBaseline(TextBaseline baseline) {
assert(!needsLayout);
return null;
}
// This whole block should only be here in debug builds
bool _debugDoingThisLayout = false;
bool _debugCanParentUseSize;
......@@ -348,6 +375,12 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox
return super.getMaxIntrinsicHeight(constraints);
}
double getDistanceToActualBaseline(TextBaseline baseline) {
if (child != null)
return child.getDistanceToActualBaseline(baseline);
return super.getDistanceToActualBaseline(baseline);
}
void performLayout() {
if (child != null) {
child.layout(constraints, parentUsesSize: true);
......@@ -585,6 +618,20 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi
canvas.paintChild(child, child.parentData.position);
}
double getDistanceToActualBaseline(TextBaseline baseline) {
double result;
if (child != null) {
assert(!needsLayout);
result = child.getDistanceToActualBaseline(baseline);
assert(child.parentData is BoxParentData);
if (result != null)
result += child.parentData.position.y;
} else {
result = super.getDistanceToActualBaseline(baseline);
}
return result;
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null) {
assert(child.parentData is BoxParentData);
......@@ -1089,6 +1136,38 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
// DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS
abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, ParentDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRenderObjectMixin<ChildType, ParentDataType> {
double defaultGetDistanceToFirstActualBaseline(TextBaseline baseline) {
assert(!needsLayout);
RenderBox child = firstChild;
while (child != null) {
assert(child.parentData is ParentDataType);
double result = child.getDistanceToActualBaseline(baseline);
if (result != null)
return result + child.parentData.position.y;
child = child.parentData.nextSibling;
}
return null;
}
double defaultGetDistanceToHighestActualBaseline(TextBaseline baseline) {
assert(!needsLayout);
double result;
RenderBox child = firstChild;
while (child != null) {
assert(child.parentData is ParentDataType);
double candidate = child.getDistanceToActualBaseline(baseline);
if (candidate != null) {
candidate += child.parentData.position.x;
if (result != null)
result = math.min(result, candidate);
else
result = candidate;
}
child = child.parentData.nextSibling;
}
return result;
}
void defaultHitTestChildren(HitTestResult result, { Point position }) {
// the x, y parameters have the top left of the node's box as the origin
ChildType child = lastChild;
......
......@@ -110,6 +110,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
} else {
inflexibleSpace += childSize(child, childConstraints);
}
assert(child.parentData is FlexBoxParentData);
child = child.parentData.nextSibling;
}
double mainSize = maxFlexFractionSoFar * totalFlex + inflexibleSpace;
......@@ -172,6 +173,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
inflexibleSpace += mainSize;
maxCrossSize = math.max(maxCrossSize, crossSize);
}
assert(child.parentData is FlexBoxParentData);
child = child.parentData.nextSibling;
}
......@@ -199,6 +201,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
}
maxCrossSize = math.max(maxCrossSize, crossSize);
}
assert(child.parentData is FlexBoxParentData);
child = child.parentData.nextSibling;
}
......@@ -243,6 +246,13 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
childSize: (c, innerConstraints) => c.getMaxIntrinsicHeight(innerConstraints));
}
double getDistanceToActualBaseline(TextBaseline baseline) {
assert(!needsLayout);
if (_direction == FlexDirection.horizontal)
return defaultGetDistanceToHighestActualBaseline(baseline);
return defaultGetDistanceToFirstActualBaseline(baseline);
}
int _getFlex(RenderBox child) {
assert(child.parentData is FlexBoxParentData);
return child.parentData.flex != null ? child.parentData.flex : 0;
......@@ -267,6 +277,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
double freeSpace = mainSize;
RenderBox child = firstChild;
while (child != null) {
assert(child.parentData is FlexBoxParentData);
totalChildren++;
int flex = _getFlex(child);
if (flex > 0) {
......@@ -306,6 +317,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
usedSpace += _getMainSize(child);
crossSize = math.max(crossSize, _getCrossSize(child));
}
assert(child.parentData is FlexBoxParentData);
child = child.parentData.nextSibling;
}
......@@ -352,6 +364,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
double childMainPosition = leadingSpace;
child = firstChild;
while (child != null) {
assert(child.parentData is FlexBoxParentData);
double childCrossPosition;
switch (_alignItems) {
case FlexAlignItems.flexStart:
......
......@@ -154,6 +154,16 @@ class RenderParagraph extends RenderBox {
return _getIntrinsicHeight(constraints);
}
double getDistanceToActualBaseline(TextBaseline baseline) {
assert(!needsLayout);
_layout(constraints);
sky.Element root = _layoutRoot.rootElement;
switch (baseline) {
case TextBaseline.alphabetic: return root.alphabeticBaseline;
case TextBaseline.ideographic: return root.ideographicBaseline;
}
}
void performLayout() {
_layout(constraints);
sky.Element root = _layoutRoot.rootElement;
......
......@@ -107,6 +107,10 @@ class RenderStack extends RenderBox with ContainerRenderObjectMixin<RenderBox, S
return height;
}
double getDistanceToActualBaseline(TextBaseline baseline) {
return defaultGetDistanceToHighestActualBaseline(baseline);
}
void performLayout() {
bool hasNonPositionedChildren = false;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册