gecko/layout/generic/nsRubyTextContainerFrame.cpp

180 lines
6.3 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/* rendering object for CSS "display: ruby-text-container" */
#include "nsRubyTextContainerFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
#include "WritingModes.h"
#include "mozilla/UniquePtr.h"
//----------------------------------------------------------------------
// Frame class boilerplate
// =======================
NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame)
NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame)
nsContainerFrame*
NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsRubyTextContainerFrame(aContext);
}
//----------------------------------------------------------------------
// nsRubyTextContainerFrame Method Implementations
// ===============================================
nsIAtom*
nsRubyTextContainerFrame::GetType() const
{
return nsGkAtoms::rubyTextContainerFrame;
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult);
}
#endif
void
nsRubyTextContainerFrame::BeginRTCLineLayout(nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState)
{
// Construct block reflow state and line layout
nscoord consumedBSize = GetConsumedBSize();
ClearLineCursor();
mISize = 0;
nsBlockReflowState state(aReflowState, aPresContext, this, true, true,
false, consumedBSize);
NS_ASSERTION(!mLines.empty(),
"There should be at least one line in the ruby text container");
line_iterator firstLine = begin_lines();
mLineLayout = mozilla::MakeUnique<nsLineLayout>(
state.mPresContext,
state.mReflowState.mFloatManager,
&state.mReflowState, &firstLine);
mLineLayout->Init(&state, state.mMinLineHeight, state.mLineNumber);
mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
mozilla::LogicalRect lineRect(state.mContentArea);
nscoord iStart = lineRect.IStart(lineWM);
nscoord availISize = lineRect.ISize(lineWM);
nscoord availBSize = NS_UNCONSTRAINEDSIZE;
mLineLayout->BeginLineReflow(iStart, state.mBCoord,
availISize, availBSize,
false,
false,
lineWM, state.mContainerWidth);
}
void
nsRubyTextContainerFrame::ReflowRubyTextFrame(
nsRubyTextFrame* rtFrame,
nsIFrame* rbFrame,
nscoord baseStart,
nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState)
{
nsReflowStatus frameReflowStatus;
nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
mozilla::WritingMode lineWM = mLineLayout->GetWritingMode();
mozilla::LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
aReflowState.AvailableHeight());
nsHTMLReflowState childReflowState(aPresContext, aReflowState, rtFrame, availSize);
// Determine the inline coordinate for the text frame by centering over
// the corresponding base frame
int baseWidth;
if (rbFrame) {
baseWidth = rbFrame->ISize();
// If this is the last ruby annotation, it gets paired with ALL remaining
// ruby bases
if (!rtFrame->GetNextSibling()) {
rbFrame = rbFrame->GetNextSibling();
while (rbFrame) {
baseWidth += rbFrame->ISize();
rbFrame = rbFrame->GetNextSibling();
}
}
} else {
baseWidth = 0;
}
int baseCenter = baseStart + baseWidth / 2;
// FIXME: Find a way to avoid using GetPrefISize here, potentially by moving
// the frame after it has reflowed.
nscoord ICoord = baseCenter - rtFrame->GetPrefISize(aReflowState.rendContext) / 2;
if (ICoord > mLineLayout->GetCurrentICoord()) {
mLineLayout->AdvanceICoord(ICoord - mLineLayout->GetCurrentICoord());
}
bool pushedFrame;
mLineLayout->ReflowFrame(rtFrame, frameReflowStatus,
&metrics, pushedFrame);
NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented");
mISize += metrics.ISize(lineWM);
rtFrame->SetSize(nsSize(metrics.ISize(lineWM), metrics.BSize(lineWM)));
FinishReflowChild(rtFrame, aPresContext, metrics, &childReflowState, 0, 0,
NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW);
}
/* virtual */ void
nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
// All rt children have already been reflowed. All we need to do is clean up
// the line layout.
aStatus = NS_FRAME_COMPLETE;
mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
mozilla::WritingMode frameWM = aReflowState.GetWritingMode();
mozilla::LogicalMargin borderPadding =
aReflowState.ComputedLogicalBorderPadding();
aDesiredSize.ISize(lineWM) = mISize;
nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
borderPadding, lineWM, frameWM);
nscoord bsize = aDesiredSize.BSize(lineWM);
if (!mLines.empty()) {
// Okay to use BlockStartAscent because it has just been correctly set by
// nsLayoutUtils::SetBSizeFromFontMetrics.
mLines.begin()->SetLogicalAscent(aDesiredSize.BlockStartAscent());
mLines.begin()->SetBounds(aReflowState.GetWritingMode(), 0, 0, mISize,
bsize, mISize);
}
if (mLineLayout) {
mLineLayout->EndLineReflow();
mLineLayout = nullptr;
}
}