InlineFormattingContextGeometry.cpp [plain text]
#include "config.h"
#include "InlineFormattingContext.h"
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "FormattingContext.h"
#include "InlineFormattingState.h"
#include "LayoutBox.h"
#include "LayoutContainer.h"
#include "LayoutState.h"
#include "TextUtil.h"
namespace WebCore {
namespace Layout {
WidthAndMargin InlineFormattingContext::Geometry::inlineBlockWidthAndMargin(LayoutState& layoutState, const Box& formattingContextRoot)
{
ASSERT(formattingContextRoot.isInFlow());
if (formattingContextRoot.replaced())
return inlineReplacedWidthAndMargin(layoutState, formattingContextRoot);
auto& containingBlock = *formattingContextRoot.containingBlock();
auto containingBlockWidth = layoutState.displayBoxForLayoutBox(containingBlock).contentBoxWidth();
auto width = computedValueIfNotAuto(formattingContextRoot.style().logicalWidth(), containingBlockWidth);
if (!width)
width = shrinkToFitWidth(layoutState, formattingContextRoot);
auto computedHorizontalMargin = Geometry::computedHorizontalMargin(layoutState, formattingContextRoot);
return WidthAndMargin { *width, { computedHorizontalMargin.start.valueOr(0_lu), computedHorizontalMargin.end.valueOr(0_lu) }, computedHorizontalMargin };
}
HeightAndMargin InlineFormattingContext::Geometry::inlineBlockHeightAndMargin(const LayoutState& layoutState, const Box& layoutBox)
{
ASSERT(layoutBox.isInFlow());
if (layoutBox.replaced())
return inlineReplacedHeightAndMargin(layoutState, layoutBox);
return complicatedCases(layoutState, layoutBox);
}
static LayoutUnit adjustedLineLogicalLeft(TextAlignMode align, LayoutUnit lineLogicalLeft, LayoutUnit remainingWidth)
{
switch (align) {
case TextAlignMode::Left:
case TextAlignMode::WebKitLeft:
case TextAlignMode::Start:
return lineLogicalLeft;
case TextAlignMode::Right:
case TextAlignMode::WebKitRight:
case TextAlignMode::End:
return lineLogicalLeft + std::max(remainingWidth, 0_lu);
case TextAlignMode::Center:
case TextAlignMode::WebKitCenter:
return lineLogicalLeft + std::max(remainingWidth / 2, 0_lu);
case TextAlignMode::Justify:
ASSERT_NOT_REACHED();
break;
}
ASSERT_NOT_REACHED();
return lineLogicalLeft;
}
void InlineFormattingContext::Geometry::justifyRuns(Line& line)
{
auto& inlineRuns = line.runs();
auto& lastInlineRun = inlineRuns.last();
auto expansionBehavior = lastInlineRun.expansionOpportunity().behavior;
expansionBehavior ^= AllowTrailingExpansion;
expansionBehavior |= ForbidTrailingExpansion;
lastInlineRun.expansionOpportunity().behavior = expansionBehavior;
auto widthToDistribute = line.availableWidth();
if (widthToDistribute <= 0)
return;
auto expansionOpportunities = 0;
for (auto& inlineRun : inlineRuns)
expansionOpportunities += inlineRun.expansionOpportunity().count;
if (!expansionOpportunities)
return;
float expansion = widthToDistribute.toFloat() / expansionOpportunities;
LayoutUnit accumulatedExpansion;
for (auto& inlineRun : inlineRuns) {
auto expansionForRun = inlineRun.expansionOpportunity().count * expansion;
inlineRun.expansionOpportunity().expansion = expansionForRun;
inlineRun.setLogicalLeft(inlineRun.logicalLeft() + accumulatedExpansion);
inlineRun.setLogicalWidth(inlineRun.logicalWidth() + expansionForRun);
accumulatedExpansion += expansionForRun;
}
}
void InlineFormattingContext::Geometry::computeExpansionOpportunities(Line& line, const InlineRunProvider::Run& run, InlineRunProvider::Run::Type lastRunType)
{
auto isExpansionOpportunity = [](auto currentRunIsWhitespace, auto lastRunIsWhitespace) {
return currentRunIsWhitespace || (!currentRunIsWhitespace && !lastRunIsWhitespace);
};
auto expansionBehavior = [](auto isAtExpansionOpportunity) {
ExpansionBehavior expansionBehavior = AllowTrailingExpansion;
expansionBehavior |= isAtExpansionOpportunity ? ForbidLeadingExpansion : AllowLeadingExpansion;
return expansionBehavior;
};
auto isAtExpansionOpportunity = isExpansionOpportunity(run.isWhitespace(), lastRunType == InlineRunProvider::Run::Type::Whitespace);
auto& currentInlineRun = line.runs().last();
auto& expansionOpportunity = currentInlineRun.expansionOpportunity();
if (isAtExpansionOpportunity)
++expansionOpportunity.count;
expansionOpportunity.behavior = expansionBehavior(isAtExpansionOpportunity);
}
void InlineFormattingContext::Geometry::alignRuns(TextAlignMode textAlign, Line& line, IsLastLine isLastLine)
{
auto adjutedTextAlignment = textAlign != TextAlignMode::Justify ? textAlign : isLastLine == IsLastLine::No ? TextAlignMode::Justify : TextAlignMode::Left;
if (adjutedTextAlignment == TextAlignMode::Justify) {
justifyRuns(line);
return;
}
auto lineLogicalLeft = line.contentLogicalLeft();
auto adjustedLogicalLeft = adjustedLineLogicalLeft(adjutedTextAlignment, lineLogicalLeft, line.availableWidth());
if (adjustedLogicalLeft == lineLogicalLeft)
return;
auto delta = adjustedLogicalLeft - lineLogicalLeft;
for (auto& inlineRun : line.runs())
inlineRun.setLogicalLeft(inlineRun.logicalLeft() + delta);
}
LayoutUnit InlineFormattingContext::Geometry::runWidth(const InlineContent& inlineContent, const InlineItem& inlineItem, ItemPosition from, unsigned length, LayoutUnit contentLogicalLeft)
{
LayoutUnit width;
auto startPosition = from;
auto iterator = inlineContent.find(const_cast<InlineItem*>(&inlineItem));
#if !ASSERT_DISABLED
auto inlineItemEnd = inlineContent.end();
#endif
while (length) {
ASSERT(iterator != inlineItemEnd);
auto& currentInlineItem = **iterator;
auto endPosition = std::min<ItemPosition>(startPosition + length, currentInlineItem.textContent().length());
auto textWidth = TextUtil::width(currentInlineItem, startPosition, endPosition, contentLogicalLeft);
contentLogicalLeft += textWidth;
width += textWidth;
length -= (endPosition - startPosition);
startPosition = 0;
++iterator;
}
return width;
}
}
}
#endif