static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c) { if (c.isNull()) return VisiblePosition(); RootInlineBox* rootBox = rootBoxForLine(c); if (!rootBox) { // There are VisiblePositions at offset 0 in blocks without // RootInlineBoxes, like empty editable blocks and bordered blocks. Position p = c.deepEquivalent(); if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) return c; return VisiblePosition(); } InlineBox* logicalEndBox; Node* logicalEndNode; getLogicalEndBoxAndNode(rootBox, logicalEndBox, logicalEndNode); if (!logicalEndNode) return VisiblePosition(); int endOffset = 1; if (logicalEndNode->hasTagName(brTag)) endOffset = 0; else if (logicalEndBox->isInlineTextBox()) { InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox); endOffset = endTextBox->start(); if (!endTextBox->isLineBreak()) endOffset += endTextBox->len(); } return VisiblePosition(logicalEndNode, endOffset, VP_UPSTREAM_IF_POSSIBLE); }
bool RootInlineBox::isHyphenated() const { for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) { if (box->isInlineTextBox()) { if (toInlineTextBox(box)->hasHyphen()) return true; } } return false; }
PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::previousOnLine() const { ASSERT(!m_inlineTextBox || !m_inlineTextBox->layoutObject().needsLayout()); if (!m_inlineTextBox) return nullptr; InlineBox* previous = m_inlineTextBox->prevOnLine(); if (previous && previous->isInlineTextBox()) return getOrCreate(&toInlineTextBox(previous)->layoutObject(), toInlineTextBox(previous)); return nullptr; }
PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::nextOnLine() const { ASSERT(!m_inlineTextBox || !m_inlineTextBox->layoutObject().needsLayout()); if (!m_inlineTextBox) return nullptr; InlineBox* next = m_inlineTextBox->nextOnLine(); if (next && next->isInlineTextBox()) return getOrCreate(&toInlineTextBox(next)->layoutObject(), toInlineTextBox(next)); return nullptr; }
static VisiblePosition endPositionForLine(const VisiblePosition& c) { if (c.isNull()) return VisiblePosition(); RootInlineBox *rootBox = rootBoxForLine(c); if (!rootBox) { // There are VisiblePositions at offset 0 in blocks without // RootInlineBoxes, like empty editable blocks and bordered blocks. Position p = c.deepEquivalent(); if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0) return c; return VisiblePosition(); } // Generated content (e.g. list markers and CSS :before and :after // pseudoelements) have no corresponding DOM element, and so cannot be // represented by a VisiblePosition. Use whatever precedes instead. Node *endNode; InlineBox *endBox = rootBox->lastLeafChild(); while (1) { if (!endBox) return VisiblePosition(); RenderObject *endRenderer = endBox->renderer(); if (!endRenderer) return VisiblePosition(); endNode = endRenderer->node(); if (endNode) break; endBox = endBox->prevLeafChild(); } int endOffset = 1; if (endNode->hasTagName(brTag)) { endOffset = 0; } else if (endBox->isInlineTextBox()) { InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox); endOffset = endTextBox->start(); if (!endTextBox->isLineBreak()) endOffset += endTextBox->len(); } return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE); }
static VisiblePosition startPositionForLine(const VisiblePosition& c) { if (c.isNull()) return VisiblePosition(); RootInlineBox *rootBox = rootBoxForLine(c); if (!rootBox) { // There are VisiblePositions at offset 0 in blocks without // RootInlineBoxes, like empty editable blocks and bordered blocks. Position p = c.deepEquivalent(); if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0) return positionAvoidingFirstPositionInTable(c); return VisiblePosition(); } // Generated content (e.g. list markers and CSS :before and :after // pseudoelements) have no corresponding DOM element, and so cannot be // represented by a VisiblePosition. Use whatever follows instead. InlineBox *startBox = rootBox->firstLeafChild(); Node *startNode; while (1) { if (!startBox) return VisiblePosition(); RenderObject *startRenderer = startBox->renderer(); if (!startRenderer) return VisiblePosition(); startNode = startRenderer->node(); if (startNode) break; startBox = startBox->nextLeafChild(); } int startOffset = 0; if (startBox->isInlineTextBox()) { InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox); startOffset = startTextBox->start(); } VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM); return positionAvoidingFirstPositionInTable(visPos); }
void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, int& topPosition, int& bottomPosition) { if (isRootInlineBox()) { setYPos(y + maxAscent - baseline());// Place our root box. // CSS2: 10.8.1 - line-height on the block level element specifies the *minimum* // height of the generated line box if (hasTextChildren() && maxHeight < object()->lineHeight(m_firstLine)) maxHeight = object()->lineHeight(m_firstLine); } for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->object()->isPositioned()) continue; // Positioned placeholders don't affect calculations. // Adjust boxes to use their real box y/height and not the logical height (as dictated by // line-height). if (curr->isInlineFlowBox()) static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(y, maxHeight, maxAscent, strictMode, topPosition, bottomPosition); bool childAffectsTopBottomPos = true; if (curr->yPos() == PositionTop) curr->setYPos(y); else if (curr->yPos() == PositionBottom) curr->setYPos(y + maxHeight - curr->height()); else { if (!strictMode && !curr->hasTextDescendant()) childAffectsTopBottomPos = false; curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline()); } int newY = curr->yPos(); int newHeight = curr->height(); int newBaseline = curr->baseline(); int overflowTop = 0; int overflowBottom = 0; if (curr->isInlineTextBox() || curr->isInlineFlowBox()) { const QFontMetrics &fm = curr->object()->fontMetrics( m_firstLine ); #ifdef APPLE_CHANGES newBaseline = fm.ascent(); newY += curr->baseline() - newBaseline; newHeight = newBaseline+fm.descent(); #else // only adjust if the leading delta is superior to the font's natural leading if ( kAbs(fm.ascent() - curr->baseline()) > fm.leading()/2 ) { int ascent = fm.ascent()+fm.leading()/2; newBaseline = ascent; newY += curr->baseline() - newBaseline; newHeight = fm.lineSpacing(); } #endif for (ShadowData* shadow = curr->object()->style()->textShadow(); shadow; shadow = shadow->next) { overflowTop = kMin(overflowTop, shadow->y - shadow->blur); overflowBottom = kMax(overflowBottom, shadow->y + shadow->blur); } 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 { newY += curr->object()->marginTop(); newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom()); overflowTop = curr->object()->overflowTop(); overflowBottom = curr->object()->overflowHeight() - newHeight; } curr->setYPos(newY); curr->setHeight(newHeight); curr->setBaseline(newBaseline); if (childAffectsTopBottomPos) { topPosition = kMin(topPosition, newY + overflowTop); bottomPosition = kMax(bottomPosition, newY + newHeight + overflowBottom); } } if (isRootInlineBox()) { const QFontMetrics &fm = object()->fontMetrics( m_firstLine ); #ifdef APPLE_CHANGES setHeight(fm.ascent()+fm.descent()); setYPos(yPos() + baseline() - fm.ascent()); setBaseline(fm.ascent()); #else if ( kAbs(fm.ascent() - baseline()) > fm.leading()/2 ) { int ascent = fm.ascent()+fm.leading()/2; setHeight(fm.lineSpacing()); setYPos(yPos() + baseline() - ascent); setBaseline(ascent); } #endif if (hasTextDescendant() || strictMode) { if (yPos() < topPosition) topPosition = yPos(); if (yPos() + height() > bottomPosition) bottomPosition = yPos() + height(); } } }