diff options
author | Russell Brenner <russellbrenner@google.com> | 2010-11-18 17:33:13 -0800 |
---|---|---|
committer | Russell Brenner <russellbrenner@google.com> | 2010-12-02 13:47:21 -0800 |
commit | 6b70adc33054f8aee8c54d0f460458a9df11b8a5 (patch) | |
tree | 103a13998c33944d6ab3b8318c509a037e639460 /WebCore/rendering/InlineFlowBox.cpp | |
parent | bdf4ebc8e70b2d221b6ee7a65660918ecb1d33aa (diff) | |
download | external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.zip external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.tar.gz external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.tar.bz2 |
Merge WebKit at r72274: Initial merge by git.
Change-Id: Ie51f0b4a16da82942bd516dce59cfb79ebbe25fb
Diffstat (limited to 'WebCore/rendering/InlineFlowBox.cpp')
-rw-r--r-- | WebCore/rendering/InlineFlowBox.cpp | 230 |
1 files changed, 185 insertions, 45 deletions
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp index 8525673..e67c751 100644 --- a/WebCore/rendering/InlineFlowBox.cpp +++ b/WebCore/rendering/InlineFlowBox.cpp @@ -35,6 +35,7 @@ #include "RenderTableCell.h" #include "RootInlineBox.h" #include "Text.h" +#include "VerticalPositionCache.h" #include <math.h> @@ -359,6 +360,43 @@ int InlineFlowBox::placeBoxesInInlineDirection(int logicalLeft, bool& needsWordS return logicalLeft; } +bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap& textBoxDataMap) const +{ + if (isHorizontal()) + return false; + + if (renderer()->style(m_firstLine)->font().primaryFont()->orientation() == Vertical) + return true; + + for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { + if (curr->renderer()->isPositioned()) + continue; // Positioned placeholders don't affect calculations. + + if (curr->isInlineFlowBox()) { + if (static_cast<InlineFlowBox*>(curr)->requiresIdeographicBaseline(textBoxDataMap)) + return true; + } else { + if (curr->renderer()->style(m_firstLine)->font().primaryFont()->orientation() == Vertical) + return true; + + const Vector<const SimpleFontData*>* usedFonts = 0; + if (curr->isInlineTextBox()) { + GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr)); + usedFonts = it == textBoxDataMap.end() ? 0 : &it->second.first; + } + + if (usedFonts) { + for (size_t i = 0; i < usedFonts->size(); ++i) { + if (usedFonts->at(i)->orientation() == Vertical) + return true; + } + } + } + } + + return false; +} + void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom) { @@ -387,29 +425,102 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, } } -static int verticalPositionForBox(InlineBox* curr, bool firstLine) +static int verticalPositionForBox(InlineBox* box, FontBaseline baselineType, bool firstLine, VerticalPositionCache& verticalPositionCache) { - if (curr->renderer()->isText()) - return curr->parent()->logicalTop(); - if (curr->renderer()->isBox()) - return toRenderBox(curr->renderer())->verticalPosition(firstLine); - return toRenderInline(curr->renderer())->verticalPositionFromCache(firstLine); + if (box->renderer()->isText()) + return box->parent()->logicalTop(); + + RenderBoxModelObject* renderer = box->boxModelObject(); + ASSERT(renderer->isInline()); + if (!renderer->isInline()) + return 0; + + // This method determines the vertical position for inline elements. + if (firstLine && !renderer->document()->usesFirstLineRules()) + firstLine = false; + + // Check the cache. + bool isRenderInline = renderer->isRenderInline(); + if (isRenderInline && !firstLine) { + int verticalPosition = verticalPositionCache.get(renderer, baselineType); + if (verticalPosition != PositionUndefined) + return verticalPosition; + } + + int verticalPosition = 0; + EVerticalAlign verticalAlign = renderer->style()->verticalAlign(); + if (verticalAlign == TOP) + verticalPosition = PositionTop; + else if (verticalAlign == BOTTOM) + verticalPosition = PositionBottom; + else { + RenderObject* parent = renderer->parent(); + if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM) + verticalPosition = box->parent()->logicalTop(); + + if (verticalAlign != BASELINE) { + const Font& font = parent->style(firstLine)->font(); + int fontSize = font.pixelSize(); + + LineDirectionMode lineDirection = parent->style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; + + if (verticalAlign == SUB) + verticalPosition += fontSize / 5 + 1; + else if (verticalAlign == SUPER) + verticalPosition -= fontSize / 3 + 1; + else if (verticalAlign == TEXT_TOP) + verticalPosition += renderer->baselinePosition(baselineType, firstLine, lineDirection) - font.ascent(baselineType); + else if (verticalAlign == MIDDLE) + verticalPosition += -static_cast<int>(font.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); + else if (verticalAlign == TEXT_BOTTOM) { + verticalPosition += font.descent(baselineType); + // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case. + if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable()) + verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType, firstLine, lineDirection)); + } else if (verticalAlign == BASELINE_MIDDLE) + verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); + else if (verticalAlign == LENGTH) + verticalPosition -= renderer->style()->verticalAlignLength().calcValue(renderer->lineHeight(firstLine, lineDirection)); + } + } + + // Store the cached value. + if (isRenderInline && !firstLine) + verticalPositionCache.set(renderer, baselineType, verticalPosition); + + return verticalPosition; } void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, - int& maxAscent, int& maxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) + int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, + bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, + FontBaseline baselineType, VerticalPositionCache& verticalPositionCache) { + // The primary purpose of this function is to compute the maximal ascent and descent values for + // a line. + // + // The maxAscent value represents the distance of the highest point of any box (including line-height) from + // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box + // (also including line-height) from the root box baseline. These values can be negative. + // + // A secondary purpose of this function is to store the offset of very box's baseline from the root box's + // baseline. This information is cached in the logicalTop() of every box. We're effectively just using + // the logicalTop() as scratch space. if (isRootInlineBox()) { // Examine our root box. int height = lineHeight(); - int baseline = baselinePosition(); + int baseline = baselinePosition(baselineType); if (hasTextChildren() || strictMode) { int ascent = baseline; int descent = height - ascent; - if (maxAscent < ascent) + if (maxAscent < ascent || !setMaxAscent) { maxAscent = ascent; - if (maxDescent < descent) + setMaxAscent = true; + } + if (maxDescent < descent || !setMaxDescent) { maxDescent = descent; + setMaxDescent = true; + } } } @@ -418,7 +529,18 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi continue; // Positioned placeholders don't affect calculations. bool isInlineFlow = curr->isInlineFlowBox(); - + + // Because a box can be positioned such that it ends up fully above or fully below the + // root line box, we only consider it to affect the maxAscent and maxDescent values if some + // part of the box (EXCLUDING line-height) is above (for ascent) or below (for descent) the root box's baseline. + bool affectsAscent = false; + bool affectsDescent = false; + + // The verticalPositionForBox function returns the distance between the child box's baseline + // and the root box's baseline. The value is negative if the child box's baseline is above the + // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline. + curr->setLogicalTop(verticalPositionForBox(curr, baselineType, m_firstLine, verticalPositionCache)); + int lineHeight; int baseline; Vector<const SimpleFontData*>* usedFonts = 0; @@ -427,39 +549,45 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi usedFonts = it == textBoxDataMap.end() ? 0 : &it->second.first; } - if (usedFonts) { + if (usedFonts && curr->renderer()->style(m_firstLine)->lineHeight().isNegative()) { usedFonts->append(curr->renderer()->style(m_firstLine)->font().primaryFont()); Length parentLineHeight = curr->renderer()->parent()->style()->lineHeight(); - if (parentLineHeight.isNegative()) { - int baselineToBottom = 0; - baseline = 0; - for (size_t i = 0; i < usedFonts->size(); ++i) { - int halfLeading = (usedFonts->at(i)->lineSpacing() - usedFonts->at(i)->ascent() - usedFonts->at(i)->descent()) / 2; - baseline = max(baseline, halfLeading + usedFonts->at(i)->ascent()); - baselineToBottom = max(baselineToBottom, usedFonts->at(i)->lineSpacing() - usedFonts->at(i)->ascent() - usedFonts->at(i)->descent() - halfLeading); - } - lineHeight = baseline + baselineToBottom; - } else if (parentLineHeight.isPercent()) { - lineHeight = parentLineHeight.calcMinValue(curr->renderer()->style()->fontSize()); - baseline = 0; - for (size_t i = 0; i < usedFonts->size(); ++i) { - int halfLeading = (lineHeight - usedFonts->at(i)->ascent() - usedFonts->at(i)->descent()) / 2; - baseline = max(baseline, halfLeading + usedFonts->at(i)->ascent()); - } - } else { - lineHeight = parentLineHeight.value(); - baseline = 0; - for (size_t i = 0; i < usedFonts->size(); ++i) { - int halfLeading = (lineHeight - usedFonts->at(i)->ascent() - usedFonts->at(i)->descent()) / 2; - baseline = max(baseline, halfLeading + usedFonts->at(i)->ascent()); + bool baselineSet = false; + baseline = 0; + int baselineToBottom = 0; + for (size_t i = 0; i < usedFonts->size(); ++i) { + int halfLeading = (usedFonts->at(i)->lineSpacing() - usedFonts->at(i)->height()) / 2; + int usedFontAscent = halfLeading + usedFonts->at(i)->ascent(baselineType); + int usedFontDescent = usedFonts->at(i)->lineSpacing() - usedFontAscent; + if (!baselineSet) { + baselineSet = true; + baseline = usedFontAscent; + baselineToBottom = usedFontDescent; + } else { + baseline = max(baseline, usedFontAscent); + baselineToBottom = max(baselineToBottom, usedFontDescent); } } + lineHeight = baseline + baselineToBottom; } else { lineHeight = curr->lineHeight(); - baseline = curr->baselinePosition(); + baseline = curr->baselinePosition(baselineType); + if (curr->isText() || isInlineFlow) { + // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline. + // If the top of our font box relative to the root box baseline is above the root box baseline, then + // we are contributing to the maxAscent value. + affectsAscent = curr->renderer()->style(m_firstLine)->font().ascent(baselineType) - curr->logicalTop() > 0; + + // Descent is similar. If any part of our font box is below the root box's baseline, then + // we contribute to the maxDescent value. + affectsDescent = curr->renderer()->style(m_firstLine)->font().descent(baselineType) + curr->logicalTop() > 0; + } else { + // Replaced elements always affect both the ascent and descent. + affectsAscent = true; + affectsDescent = true; + } } - curr->setLogicalTop(verticalPositionForBox(curr, m_firstLine)); if (curr->logicalTop() == PositionTop) { if (maxPositionTop < lineHeight) maxPositionTop = lineHeight; @@ -467,23 +595,35 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi if (maxPositionBottom < lineHeight) maxPositionBottom = lineHeight; } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasInlineDirectionBordersOrPadding() || strictMode) { + // Note that these values can be negative. Even though we only affect the maxAscent and maxDescent values + // if our box (excluding line-height) was above (for ascent) or below (for descent) the root baseline, once you factor in line-height + // the final box can end up being fully above or fully below the root box's baseline! This is ok, but what it + // means is that ascent and descent (including leading), can end up being negative. The setMaxAscent and + // setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative + // values. int ascent = baseline - curr->logicalTop(); int descent = lineHeight - ascent; - if (maxAscent < ascent) + if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) { maxAscent = ascent; - if (maxDescent < descent) + setMaxAscent = true; + } + if (affectsDescent && (maxDescent < descent || !setMaxDescent)) { maxDescent = descent; + setMaxDescent = true; + } } if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode, textBoxDataMap); + static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, + setMaxAscent, setMaxDescent, strictMode, textBoxDataMap, + baselineType, verticalPositionCache); } } -void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop) +void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop, FontBaseline baselineType) { if (isRootInlineBox()) - setLogicalTop(top + maxAscent - baselinePosition()); // Place our root box. + setLogicalTop(top + maxAscent - baselinePosition(baselineType)); // Place our root box. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isPositioned()) @@ -493,7 +633,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs // line-height). bool isInlineFlow = curr->isInlineFlowBox(); if (isInlineFlow) - static_cast<InlineFlowBox*>(curr)->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop); + static_cast<InlineFlowBox*>(curr)->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop, baselineType); bool childAffectsTopBottomPos = true; if (curr->logicalTop() == PositionTop) @@ -503,14 +643,14 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs else { if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding() && !strictMode) childAffectsTopBottomPos = false; - int posAdjust = maxAscent - curr->baselinePosition(); + int posAdjust = maxAscent - curr->baselinePosition(baselineType); curr->setLogicalTop(curr->logicalTop() + top + posAdjust); } int newLogicalTop = curr->logicalTop(); if (curr->isText() || curr->isInlineFlowBox()) { const Font& font = curr->renderer()->style(m_firstLine)->font(); - newLogicalTop += curr->baselinePosition() - font.ascent(); + newLogicalTop += curr->baselinePosition(baselineType) - font.ascent(baselineType); if (curr->isInlineFlowBox()) { RenderBoxModelObject* boxObject = toRenderBoxModelObject(curr->renderer()); newLogicalTop -= boxObject->style(m_firstLine)->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() : @@ -536,7 +676,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs if (isRootInlineBox()) { const Font& font = renderer()->style(m_firstLine)->font(); - setLogicalTop(logicalTop() + baselinePosition() - font.ascent()); + setLogicalTop(logicalTop() + baselinePosition(baselineType) - font.ascent(baselineType)); if (hasTextChildren() || strictMode) { if (!setLineTop) { |