📄 render_line.cpp
字号:
if (curr->isInlineFlowBox()) {
newHeight += curr->object()->borderTop() + curr->object()->paddingTop() +
curr->object()->borderBottom() + curr->object()->paddingBottom();
newY -= curr->object()->borderTop() + curr->object()->paddingTop();
newBaseline += curr->object()->borderTop() + curr->object()->paddingTop();
}
}
else if (!curr->object()->isBR()) {
newY += curr->object()->marginTop();
newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom());
}
curr->setYPos(newY);
curr->setHeight(newHeight);
curr->setBaseline(newBaseline);
if (childAffectsTopBottomPos) {
if (newY < topPosition)
topPosition = newY;
if (newY + newHeight > bottomPosition)
bottomPosition = newY + newHeight;
}
}
if (isRootInlineBox()) {
const QFontMetrics &fm = object()->fontMetrics( m_firstLine );
setHeight(fm.ascent()+fm.descent());
setYPos(yPos() + baseline() - fm.ascent());
setBaseline(fm.ascent());
if (hasTextChildren() || strictMode) {
if (yPos() < topPosition)
topPosition = yPos();
if (yPos() + height() > bottomPosition)
bottomPosition = yPos() + height();
}
}
}
void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos)
{
// First shrink our kids.
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->object()->isPositioned())
continue; // Positioned placeholders don't affect calculations.
if (curr->isInlineFlowBox())
static_cast<InlineFlowBox*>(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos);
}
// See if we have text children. If not, then we need to shrink ourselves to fit on the line.
if (!hasTextChildren()) {
if (yPos() < topPos)
setYPos(topPos);
if (yPos() + height() > bottomPos)
setHeight(bottomPos - yPos());
if (baseline() > height())
setBaseline(height());
}
}
bool InlineFlowBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty)
{
// Check children first.
for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
if (!curr->object()->layer() && curr->nodeAtPoint(i, x, y, tx, ty)) {
object()->setInnerNode(i);
return true;
}
}
// Now check ourselves.
QRect rect(tx + m_x, ty + m_y, m_width, m_height);
if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
object()->setInnerNode(i);
return true;
}
return false;
}
void InlineFlowBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
{
bool intersectsDamageRect = true;
int xPos = tx + m_x - object()->maximalOutlineSize(i.phase);
int w = width() + 2 * object()->maximalOutlineSize(i.phase);
if ((xPos >= i.r.x() + i.r.width()) || (xPos + w <= i.r.x()))
intersectsDamageRect = false;
if (intersectsDamageRect) {
if (i.phase == PaintActionOutline) {
// Add ourselves to the paint info struct's list of inlines that need to paint their
// outlines.
if (object()->style()->visibility() == VISIBLE && object()->style()->outlineWidth() > 0 &&
!object()->isInlineContinuation()) {
if (!i.outlineObjects)
i.outlineObjects = new QPtrDict<RenderFlow>;
if (!i.outlineObjects->find(flowObject()))
i.outlineObjects->insert(flowObject(), flowObject());
}
}
else {
// 1. Paint our background and border.
paintBackgroundAndBorder(i, tx, ty);
// 2. Paint our underline and overline.
paintDecorations(i, tx, ty, false);
}
}
// 3. Paint our children.
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (!curr->object()->layer())
curr->paint(i, tx, ty);
}
// 4. Paint our strike-through
if (intersectsDamageRect && i.phase != PaintActionOutline)
paintDecorations(i, tx, ty, true);
}
void InlineFlowBox::paintBackgrounds(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
int my, int mh, int _tx, int _ty, int w, int h)
{
if (!bgLayer)
return;
paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h);
paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h);
}
void InlineFlowBox::paintBackground(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
int my, int mh, int _tx, int _ty, int w, int h)
{
CachedImage* bg = bgLayer->backgroundImage();
bool hasBackgroundImage = bg && (bg->pixmap_size() == bg->valid_rect().size()) &&
!bg->isTransparent() && !bg->isErrorImage();
if (!hasBackgroundImage || (!prevLineBox() && !nextLineBox()) || !parent())
object()->paintBackgroundExtended(p, c, bgLayer, my, mh, _tx, _ty, w, h, borderLeft(), borderRight());
else {
// We have a background image that spans multiple lines.
// We need to adjust _tx and _ty by the width of all previous lines.
// Think of background painting on inlines as though you had one long line, a single continuous
// strip. Even though that strip has been broken up across multiple lines, you still paint it
// as though you had one single line. This means each line has to pick up the background where
// the previous line left off.
int xOffsetOnLine = 0;
for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
xOffsetOnLine += curr->width();
int startX = _tx - xOffsetOnLine;
int totalWidth = xOffsetOnLine;
for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
totalWidth += curr->width();
QRect clipRect(_tx, _ty, width(), height());
clipRect = p->xForm(clipRect);
p->save();
p->addClip(clipRect);
object()->paintBackgroundExtended(p, c, bgLayer, my, mh, startX, _ty,
totalWidth, h, borderLeft(), borderRight());
p->restore();
}
}
void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty)
{
if (!object()->shouldPaintWithinRoot(i) || object()->style()->visibility() != VISIBLE ||
i.phase != PaintActionForeground)
return;
// Move x/y to our coordinates.
_tx += m_x;
_ty += m_y;
int w = width();
int h = height();
int my = kMax(_ty, i.r.y());
int mh;
if (_ty < i.r.y())
mh= kMax(0, h - (i.r.y() - _ty));
else
mh = kMin(i.r.height(), h);
QPainter* p = i.p;
// You can use p::first-line to specify a background. If so, the root line boxes for
// a line may actually have to paint a background.
RenderStyle* styleToUse = object()->style(m_firstLine);
if ((!parent() && m_firstLine && styleToUse != object()->style()) ||
(parent() && object()->shouldPaintBackgroundOrBorder())) {
QColor c = styleToUse->backgroundColor();
paintBackgrounds(p, c, styleToUse->backgroundLayers(), my, mh, _tx, _ty, w, h);
// :first-line cannot be used to put borders on a line. Always paint borders with our
// non-first-line style.
if (parent() && object()->style()->hasBorder())
object()->paintBorder(p, _tx, _ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge());
}
}
static bool shouldDrawDecoration(RenderObject* obj)
{
bool shouldDraw = false;
for (RenderObject* curr = obj->firstChild();
curr; curr = curr->nextSibling()) {
if (curr->isInlineFlow()) {
shouldDraw = true;
break;
}
else if (curr->isText() && !curr->isBR() && (curr->style()->whiteSpace() == PRE ||
!curr->element() || !curr->element()->containsOnlyWhitespace())) {
shouldDraw = true;
break;
}
}
return shouldDraw;
}
void InlineFlowBox::paintDecorations(RenderObject::PaintInfo& i, int _tx, int _ty, bool paintedChildren)
{
// Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in
// almost-strict mode or strict mode).
if (object()->style()->htmlHacks() || !object()->shouldPaintWithinRoot(i) ||
object()->style()->visibility() != VISIBLE)
return;
QPainter* p = i.p;
_tx += m_x;
_ty += m_y;
RenderStyle* styleToUse = object()->style(m_firstLine);
int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect();
if (deco != TDNONE &&
((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
shouldDrawDecoration(object())) {
int x = m_x + borderLeft() + paddingLeft();
int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
RootInlineBox* rootLine = root();
if (rootLine->ellipsisBox()) {
int ellipsisX = rootLine->ellipsisBox()->xPos();
int ellipsisWidth = rootLine->ellipsisBox()->width();
// FIXME: Will need to work with RTL
if (rootLine == this) {
if (x + w >= ellipsisX + ellipsisWidth)
w -= (x + w - ellipsisX - ellipsisWidth);
}
else {
if (x >= ellipsisX)
return;
if (x + w >= ellipsisX)
w -= (x + w - ellipsisX);
}
}
#if APPLE_CHANGES
// Set up the appropriate text-shadow effect for the decoration.
// FIXME: Support multiple shadow effects. Need more from the CG API before we can do this.
bool setShadow = false;
if (styleToUse->textShadow()) {
p->setShadow(styleToUse->textShadow()->x, styleToUse->textShadow()->y,
styleToUse->textShadow()->blur, styleToUse->textShadow()->color);
setShadow = true;
}
#endif
// We must have child boxes and have decorations defined.
_tx += borderLeft() + paddingLeft();
QColor underline, overline, linethrough;
underline = overline = linethrough = styleToUse->color();
if (!parent())
object()->getTextDecorationColors(deco, underline, overline, linethrough);
if (styleToUse->font() != p->font())
p->setFont(styleToUse->font());
if (deco & UNDERLINE && !paintedChildren) {
p->setPen(underline);
p->drawLineForText(_tx, _ty, m_baseline, w);
}
if (deco & OVERLINE && !paintedChildren) {
p->setPen(overline);
p->drawLineForText(_tx, _ty, 0, w);
}
if (deco & LINE_THROUGH && paintedChildren) {
p->setPen(linethrough);
p->drawLineForText(_tx, _ty, 2*m_baseline/3, w);
}
#if APPLE_CHANGES
if (setShadow)
p->clearShadow();
#endif
}
}
InlineBox* InlineFlowBox::firstLeafChild()
{
return firstLeafChildAfterBox();
}
InlineBox* InlineFlowBox::lastLeafChild()
{
return lastLeafChildBeforeBox();
}
InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start)
{
InlineBox* leaf = 0;
for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine())
leaf = box->firstLeafChild();
if (start && !leaf && parent())
return parent()->firstLeafChildAfterBox(this);
return leaf;
}
InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start)
{
InlineBox* leaf = 0;
for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine())
leaf = box->lastLeafChild();
if (start && !leaf && parent())
return parent()->lastLeafChildBeforeBox(this);
return leaf;
}
RenderObject::SelectionState InlineFlowBox::selectionState()
{
return RenderObject::SelectionNone;
}
bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -