2001-09-29 00:14:13 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2006-03-29 22:29:03 +04:00
|
|
|
|
|
|
|
/* state and methods used while laying out a single line of a block frame */
|
|
|
|
|
2013-09-25 05:43:43 +04:00
|
|
|
// This has to be defined before nsLineLayout.h is included, because
|
|
|
|
// nsLineLayout.h has a #include for plarena.h, which needs this defined:
|
2004-07-15 21:50:34 +04:00
|
|
|
#define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
|
2013-09-25 05:43:43 +04:00
|
|
|
#include "nsLineLayout.h"
|
2004-07-15 21:50:34 +04:00
|
|
|
|
2015-06-16 02:36:11 +03:00
|
|
|
#include "LayoutLogging.h"
|
2014-01-11 05:13:09 +04:00
|
|
|
#include "SVGTextFrame.h"
|
2004-05-05 05:46:15 +04:00
|
|
|
#include "nsBlockFrame.h"
|
2014-10-24 19:28:14 +04:00
|
|
|
#include "nsFontMetrics.h"
|
1998-07-22 22:38:57 +04:00
|
|
|
#include "nsStyleConsts.h"
|
2011-12-28 00:18:48 +04:00
|
|
|
#include "nsContainerFrame.h"
|
2009-01-05 03:39:54 +03:00
|
|
|
#include "nsFloatManager.h"
|
2003-02-22 03:32:13 +03:00
|
|
|
#include "nsStyleContext.h"
|
2004-08-01 03:15:21 +04:00
|
|
|
#include "nsPresContext.h"
|
2007-01-30 03:06:41 +03:00
|
|
|
#include "nsGkAtoms.h"
|
1999-09-03 07:47:49 +04:00
|
|
|
#include "nsIContent.h"
|
2004-09-13 17:35:46 +04:00
|
|
|
#include "nsLayoutUtils.h"
|
2007-09-24 06:19:14 +04:00
|
|
|
#include "nsTextFrame.h"
|
2013-10-02 01:01:49 +04:00
|
|
|
#include "nsStyleStructInlines.h"
|
2014-03-12 00:23:50 +04:00
|
|
|
#include "nsBidiPresUtils.h"
|
2015-01-08 08:02:41 +03:00
|
|
|
#include "nsRubyFrame.h"
|
2015-04-08 02:22:34 +03:00
|
|
|
#include "nsRubyTextFrame.h"
|
2014-12-13 08:13:12 +03:00
|
|
|
#include "RubyUtils.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
1999-09-03 07:47:49 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef DEBUG
|
2014-03-12 00:23:50 +04:00
|
|
|
#undef NOISY_INLINEDIR_ALIGN
|
|
|
|
#undef NOISY_BLOCKDIR_ALIGN
|
|
|
|
#undef REALLY_NOISY_BLOCKDIR_ALIGN
|
1999-03-19 00:03:25 +03:00
|
|
|
#undef NOISY_REFLOW
|
2000-04-17 18:40:46 +04:00
|
|
|
#undef REALLY_NOISY_REFLOW
|
1999-03-19 00:03:25 +03:00
|
|
|
#undef NOISY_PUSHING
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef REALLY_NOISY_PUSHING
|
|
|
|
#undef DEBUG_ADD_TEXT
|
1999-03-20 22:38:50 +03:00
|
|
|
#undef NOISY_MAX_ELEMENT_SIZE
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
1999-03-24 18:41:49 +03:00
|
|
|
#undef NOISY_CAN_PLACE_FRAME
|
2001-04-20 01:54:35 +04:00
|
|
|
#undef NOISY_TRIM
|
|
|
|
#undef REALLY_NOISY_TRIM
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
1998-06-18 20:25:41 +04:00
|
|
|
|
2011-04-29 02:48:52 +04:00
|
|
|
using namespace mozilla;
|
|
|
|
|
1998-06-18 20:25:41 +04:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#define FIX_BUG_50257
|
|
|
|
|
2004-08-01 03:15:21 +04:00
|
|
|
nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
|
2009-01-05 03:39:54 +03:00
|
|
|
nsFloatManager* aFloatManager,
|
2007-01-18 04:20:09 +03:00
|
|
|
const nsHTMLReflowState* aOuterReflowState,
|
2014-12-06 02:05:51 +03:00
|
|
|
const nsLineList::iterator* aLine,
|
|
|
|
nsLineLayout* aBaseLineLayout)
|
1999-03-19 00:03:25 +03:00
|
|
|
: mPresContext(aPresContext),
|
2009-01-05 03:39:54 +03:00
|
|
|
mFloatManager(aFloatManager),
|
1999-03-19 00:03:25 +03:00
|
|
|
mBlockReflowState(aOuterReflowState),
|
2015-01-13 07:14:46 +03:00
|
|
|
mBaseLineLayout(aBaseLineLayout),
|
2014-11-14 08:41:14 +03:00
|
|
|
mLastOptionalBreakFrame(nullptr),
|
|
|
|
mForceBreakFrame(nullptr),
|
2012-07-30 18:20:58 +04:00
|
|
|
mBlockRS(nullptr),/* XXX temporary */
|
2014-01-23 22:26:39 +04:00
|
|
|
mLastOptionalBreakPriority(gfxBreakPriority::eNoBreak),
|
2014-11-14 08:41:14 +03:00
|
|
|
mLastOptionalBreakFrameOffset(-1),
|
|
|
|
mForceBreakFrameOffset(-1),
|
2014-03-12 00:23:50 +04:00
|
|
|
mMinLineBSize(0),
|
2012-09-28 05:56:40 +04:00
|
|
|
mTextIndent(0),
|
|
|
|
mFirstLetterStyleOK(false),
|
|
|
|
mIsTopOfPage(false),
|
|
|
|
mImpactedByFloats(false),
|
|
|
|
mLastFloatWasLetterFrame(false),
|
|
|
|
mLineIsEmpty(false),
|
|
|
|
mLineEndsInBR(false),
|
|
|
|
mNeedBackup(false),
|
|
|
|
mInFirstLine(false),
|
|
|
|
mGotLineBox(false),
|
|
|
|
mInFirstLetter(false),
|
|
|
|
mHasBullet(false),
|
|
|
|
mDirtyNextLine(false),
|
2014-12-13 03:48:30 +03:00
|
|
|
mLineAtStart(false),
|
2015-02-18 07:20:02 +03:00
|
|
|
mHasRuby(false),
|
|
|
|
mSuppressLineWrap(aOuterReflowState->frame->IsSVGText())
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2013-04-23 05:45:26 +04:00
|
|
|
MOZ_ASSERT(aOuterReflowState, "aOuterReflowState must not be null");
|
2009-01-05 03:39:54 +03:00
|
|
|
NS_ASSERTION(aFloatManager || aOuterReflowState->frame->GetType() ==
|
2006-12-26 20:47:52 +03:00
|
|
|
nsGkAtoms::letterFrame,
|
2009-01-05 03:39:54 +03:00
|
|
|
"float manager should be present");
|
2015-01-13 07:14:46 +03:00
|
|
|
MOZ_ASSERT((!!mBaseLineLayout) ==
|
|
|
|
(aOuterReflowState->frame->GetType() ==
|
|
|
|
nsGkAtoms::rubyTextContainerFrame),
|
|
|
|
"Only ruby text container frames have "
|
|
|
|
"a different base line layout");
|
1999-10-09 00:41:19 +04:00
|
|
|
MOZ_COUNT_CTOR(nsLineLayout);
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Stash away some style data that we need
|
2013-12-13 21:42:43 +04:00
|
|
|
nsBlockFrame* blockFrame = do_QueryFrame(aOuterReflowState->frame);
|
|
|
|
if (blockFrame)
|
|
|
|
mStyleText = blockFrame->StyleTextForLineLayout();
|
|
|
|
else
|
|
|
|
mStyleText = aOuterReflowState->frame->StyleText();
|
|
|
|
|
1998-06-18 20:25:41 +04:00
|
|
|
mLineNumber = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
mTotalPlacedFrames = 0;
|
2014-03-12 00:23:50 +04:00
|
|
|
mBStartEdge = 0;
|
2014-10-22 02:16:11 +04:00
|
|
|
mTrimmableISize = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2011-11-24 06:48:23 +04:00
|
|
|
mInflationMinFontSize =
|
2012-05-21 09:18:28 +04:00
|
|
|
nsLayoutUtils::InflationMinFontSizeFor(aOuterReflowState->frame);
|
2011-11-24 06:48:23 +04:00
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
// Instead of always pre-initializing the free-lists for frames and
|
|
|
|
// spans, we do it on demand so that situations that only use a few
|
2005-11-21 01:05:24 +03:00
|
|
|
// frames and spans won't waste a lot of time in unneeded
|
2002-08-14 17:00:16 +04:00
|
|
|
// initialization.
|
2004-07-15 21:50:34 +04:00
|
|
|
PL_INIT_ARENA_POOL(&mArena, "nsLineLayout", 1024);
|
2012-07-30 18:20:58 +04:00
|
|
|
mFrameFreeList = nullptr;
|
|
|
|
mSpanFreeList = nullptr;
|
2002-08-14 17:00:16 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mCurrentSpan = mRootSpan = nullptr;
|
1999-03-19 00:03:25 +03:00
|
|
|
mSpanDepth = 0;
|
|
|
|
|
2007-01-18 04:20:09 +03:00
|
|
|
if (aLine) {
|
2012-09-28 05:56:40 +04:00
|
|
|
mGotLineBox = true;
|
2007-01-18 04:20:09 +03:00
|
|
|
mLineBox = *aLine;
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-09-15 04:19:49 +04:00
|
|
|
nsLineLayout::~nsLineLayout()
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1999-10-09 00:41:19 +04:00
|
|
|
MOZ_COUNT_DTOR(nsLineLayout);
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
NS_ASSERTION(nullptr == mRootSpan, "bad line-layout user");
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2004-07-15 21:50:34 +04:00
|
|
|
PL_FinishArenaPool(&mArena);
|
|
|
|
}
|
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
// Find out if the frame has a non-null prev-in-flow, i.e., whether it
|
|
|
|
// is a continuation.
|
2011-09-29 10:19:26 +04:00
|
|
|
inline bool
|
2002-05-14 16:55:55 +04:00
|
|
|
HasPrevInFlow(nsIFrame *aFrame)
|
|
|
|
{
|
2004-09-14 06:28:03 +04:00
|
|
|
nsIFrame *prevInFlow = aFrame->GetPrevInFlow();
|
2012-07-30 18:20:58 +04:00
|
|
|
return prevInFlow != nullptr;
|
2002-05-14 16:55:55 +04:00
|
|
|
}
|
|
|
|
|
1998-06-28 02:56:09 +04:00
|
|
|
void
|
2014-03-12 00:23:50 +04:00
|
|
|
nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
|
|
|
|
nscoord aISize, nscoord aBSize,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aImpactedByFloats,
|
2011-10-18 16:51:58 +04:00
|
|
|
bool aIsTopOfPage,
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode aWritingMode,
|
2015-02-11 12:43:03 +03:00
|
|
|
const nsSize& aContainerSize)
|
1998-06-28 02:56:09 +04:00
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
NS_ASSERTION(nullptr == mRootSpan, "bad linelayout user");
|
2015-06-16 02:36:11 +03:00
|
|
|
LAYOUT_WARN_IF_FALSE(aISize != NS_UNCONSTRAINEDSIZE,
|
2015-06-16 02:36:12 +03:00
|
|
|
"have unconstrained width; this should only result from "
|
|
|
|
"very large sizes, not attempts at intrinsic width "
|
|
|
|
"calculation");
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef DEBUG
|
2014-03-12 00:23:50 +04:00
|
|
|
if ((aISize != NS_UNCONSTRAINEDSIZE) && CRAZY_SIZE(aISize)) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": Init: bad caller: width WAS %d(0x%x)\n",
|
2014-03-12 00:23:50 +04:00
|
|
|
aISize, aISize);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if ((aBSize != NS_UNCONSTRAINEDSIZE) && CRAZY_SIZE(aBSize)) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": Init: bad caller: height WAS %d(0x%x)\n",
|
2014-03-12 00:23:50 +04:00
|
|
|
aBSize, aBSize);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": BeginLineReflow: %d,%d,%d,%d impacted=%s %s\n",
|
2014-03-12 00:23:50 +04:00
|
|
|
aICoord, aBCoord, aISize, aBSize,
|
2003-10-14 01:51:02 +04:00
|
|
|
aImpactedByFloats?"true":"false",
|
1999-03-19 00:03:25 +03:00
|
|
|
aIsTopOfPage ? "top-of-page" : "");
|
|
|
|
#endif
|
2002-08-14 17:00:16 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
mSpansAllocated = mSpansFreed = mFramesAllocated = mFramesFreed = 0;
|
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2012-09-28 05:56:40 +04:00
|
|
|
mFirstLetterStyleOK = false;
|
|
|
|
mIsTopOfPage = aIsTopOfPage;
|
|
|
|
mImpactedByFloats = aImpactedByFloats;
|
1999-03-19 00:03:25 +03:00
|
|
|
mTotalPlacedFrames = 0;
|
2015-01-13 07:14:46 +03:00
|
|
|
if (!mBaseLineLayout) {
|
2014-12-10 07:57:14 +03:00
|
|
|
mLineIsEmpty = true;
|
|
|
|
mLineAtStart = true;
|
|
|
|
} else {
|
|
|
|
mLineIsEmpty = false;
|
|
|
|
mLineAtStart = false;
|
|
|
|
}
|
2012-09-28 05:56:40 +04:00
|
|
|
mLineEndsInBR = false;
|
1999-03-19 00:03:25 +03:00
|
|
|
mSpanDepth = 0;
|
2014-03-12 00:23:50 +04:00
|
|
|
mMaxStartBoxBSize = mMaxEndBoxBSize = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2012-09-28 05:56:40 +04:00
|
|
|
if (mGotLineBox) {
|
2009-08-11 06:48:42 +04:00
|
|
|
mLineBox->ClearHasBullet();
|
|
|
|
}
|
|
|
|
|
2013-02-23 14:38:15 +04:00
|
|
|
PerSpanData* psd = NewPerSpanData();
|
1999-03-19 00:03:25 +03:00
|
|
|
mCurrentSpan = mRootSpan = psd;
|
|
|
|
psd->mReflowState = mBlockReflowState;
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mIStart = aICoord;
|
|
|
|
psd->mICoord = aICoord;
|
|
|
|
psd->mIEnd = aICoord + aISize;
|
2015-02-11 12:43:03 +03:00
|
|
|
mContainerSize = aContainerSize;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2015-03-10 17:28:23 +03:00
|
|
|
// If we're in a constrained block-size frame, then we don't allow a
|
2012-12-05 08:14:56 +04:00
|
|
|
// max line box width to take effect.
|
2013-04-23 05:45:26 +04:00
|
|
|
if (!(LineContainerFrame()->GetStateBits() &
|
2015-03-10 17:28:23 +03:00
|
|
|
NS_FRAME_IN_CONSTRAINED_BSIZE)) {
|
2012-12-05 08:14:56 +04:00
|
|
|
|
|
|
|
// If the available size is greater than the maximum line box width (if
|
|
|
|
// specified), then we need to adjust the line box width to be at the max
|
|
|
|
// possible width.
|
|
|
|
nscoord maxLineBoxWidth =
|
2013-04-23 05:45:26 +04:00
|
|
|
LineContainerFrame()->PresContext()->PresShell()->MaxLineBoxWidth();
|
2012-12-05 08:14:56 +04:00
|
|
|
|
|
|
|
if (maxLineBoxWidth > 0 &&
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mIEnd - psd->mIStart > maxLineBoxWidth) {
|
|
|
|
psd->mIEnd = psd->mIStart + maxLineBoxWidth;
|
2012-12-05 08:14:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
mBStartEdge = aBCoord;
|
1999-03-22 23:45:09 +03:00
|
|
|
|
2015-02-18 07:20:02 +03:00
|
|
|
psd->mNoWrap = !mStyleText->WhiteSpaceCanWrapStyle() || mSuppressLineWrap;
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mWritingMode = aWritingMode;
|
2001-12-11 05:45:44 +03:00
|
|
|
|
|
|
|
// If this is the first line of a block then see if the text-indent
|
|
|
|
// property amounts to anything.
|
2006-10-19 05:47:47 +04:00
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowState->frame)) {
|
2010-08-31 20:05:12 +04:00
|
|
|
const nsStyleCoord &textIndent = mStyleText->mTextIndent;
|
|
|
|
nscoord pctBasis = 0;
|
|
|
|
if (textIndent.HasPercent()) {
|
|
|
|
pctBasis =
|
2015-04-19 21:03:27 +03:00
|
|
|
mBlockReflowState->GetContainingBlockContentISize(aWritingMode);
|
2001-12-11 05:45:44 +03:00
|
|
|
}
|
2010-08-31 20:05:12 +04:00
|
|
|
nscoord indent = nsRuleNode::ComputeCoordPercentCalc(textIndent, pctBasis);
|
2001-12-11 05:45:44 +03:00
|
|
|
|
2002-05-14 16:55:55 +04:00
|
|
|
mTextIndent = indent;
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mICoord += indent;
|
2001-12-11 05:45:44 +03:00
|
|
|
}
|
2014-12-15 02:33:59 +03:00
|
|
|
|
|
|
|
PerFrameData* pfd = NewPerFrameData(mBlockReflowState->frame);
|
|
|
|
pfd->mAscent = 0;
|
|
|
|
pfd->mSpan = psd;
|
|
|
|
psd->mFrame = pfd;
|
2015-01-13 12:04:41 +03:00
|
|
|
nsIFrame* frame = mBlockReflowState->frame;
|
|
|
|
if (frame->GetType() == nsGkAtoms::rubyTextContainerFrame) {
|
|
|
|
// Ruby text container won't be reflowed via ReflowFrame, hence the
|
|
|
|
// relative positioning information should be recorded here.
|
|
|
|
MOZ_ASSERT(mBaseLineLayout != this);
|
|
|
|
pfd->mRelativePos =
|
|
|
|
mBlockReflowState->mStyleDisplay->IsRelativelyPositionedStyle();
|
|
|
|
if (pfd->mRelativePos) {
|
|
|
|
MOZ_ASSERT(
|
|
|
|
mBlockReflowState->GetWritingMode() == frame->GetWritingMode(),
|
|
|
|
"mBlockReflowState->frame == frame, "
|
|
|
|
"hence they should have identical writing mode");
|
|
|
|
pfd->mOffsets = mBlockReflowState->ComputedLogicalOffsets();
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 02:56:09 +04:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::EndLineReflow()
|
1998-06-28 02:56:09 +04:00
|
|
|
{
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": EndLineReflow: width=%d\n", mRootSpan->mICoord - mRootSpan->mIStart);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
2015-01-13 07:14:46 +03:00
|
|
|
NS_ASSERTION(!mBaseLineLayout ||
|
2014-12-06 02:31:42 +03:00
|
|
|
(!mSpansAllocated && !mSpansFreed && !mSpanFreeList &&
|
|
|
|
!mFramesAllocated && !mFramesFreed && !mFrameFreeList),
|
|
|
|
"Allocated frames or spans on non-base line layout?");
|
|
|
|
|
2014-12-10 01:40:14 +03:00
|
|
|
UnlinkFrame(mRootSpan->mFrame);
|
2012-07-30 18:20:58 +04:00
|
|
|
mCurrentSpan = mRootSpan = nullptr;
|
2002-08-14 17:00:16 +04:00
|
|
|
|
|
|
|
NS_ASSERTION(mSpansAllocated == mSpansFreed, "leak");
|
|
|
|
NS_ASSERTION(mFramesAllocated == mFramesFreed, "leak");
|
|
|
|
|
|
|
|
#if 0
|
2012-08-22 19:56:38 +04:00
|
|
|
static int32_t maxSpansAllocated = NS_LINELAYOUT_NUM_SPANS;
|
|
|
|
static int32_t maxFramesAllocated = NS_LINELAYOUT_NUM_FRAMES;
|
2002-08-14 17:00:16 +04:00
|
|
|
if (mSpansAllocated > maxSpansAllocated) {
|
|
|
|
printf("XXX: saw a line with %d spans\n", mSpansAllocated);
|
|
|
|
maxSpansAllocated = mSpansAllocated;
|
|
|
|
}
|
|
|
|
if (mFramesAllocated > maxFramesAllocated) {
|
|
|
|
printf("XXX: saw a line with %d frames\n", mFramesAllocated);
|
|
|
|
maxFramesAllocated = mFramesAllocated;
|
|
|
|
}
|
|
|
|
#endif
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
// XXX swtich to a single mAvailLineWidth that we adjust as each frame
|
2014-03-12 00:23:50 +04:00
|
|
|
// on the line is placed. Each span can still have a per-span mICoord that
|
1999-03-24 18:41:49 +03:00
|
|
|
// tracks where a child frame is going in its span; they don't need a
|
2014-03-12 00:23:50 +04:00
|
|
|
// per-span mIStart?
|
1999-03-24 18:41:49 +03:00
|
|
|
|
1998-06-18 20:25:41 +04:00
|
|
|
void
|
2014-10-22 02:16:13 +04:00
|
|
|
nsLineLayout::UpdateBand(WritingMode aWM,
|
|
|
|
const LogicalRect& aNewAvailSpace,
|
2003-10-14 01:51:02 +04:00
|
|
|
nsIFrame* aFloatFrame)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2014-10-22 02:16:13 +04:00
|
|
|
// need to convert to our writing mode, because we might have a different
|
|
|
|
// mode from the caller due to dir: auto
|
|
|
|
LogicalRect availSpace = aNewAvailSpace.ConvertTo(lineWM, aWM,
|
2015-07-16 12:07:57 +03:00
|
|
|
ContainerSize());
|
2000-03-23 02:19:10 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2014-10-22 02:16:13 +04:00
|
|
|
printf("nsLL::UpdateBand %d, %d, %d, %d, (converted to %d, %d, %d, %d); frame=%p\n will set mImpacted to true\n",
|
2008-06-11 03:53:22 +04:00
|
|
|
aNewAvailSpace.x, aNewAvailSpace.y,
|
|
|
|
aNewAvailSpace.width, aNewAvailSpace.height,
|
2014-03-12 00:23:50 +04:00
|
|
|
availSpace.IStart(lineWM), availSpace.BStart(lineWM),
|
|
|
|
availSpace.ISize(lineWM), availSpace.BSize(lineWM),
|
2009-05-14 13:31:35 +04:00
|
|
|
aFloatFrame);
|
2000-03-23 02:19:10 +03:00
|
|
|
#endif
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef DEBUG
|
2014-03-12 00:23:50 +04:00
|
|
|
if ((availSpace.ISize(lineWM) != NS_UNCONSTRAINEDSIZE) &&
|
|
|
|
CRAZY_SIZE(availSpace.ISize(lineWM))) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": UpdateBand: bad caller: ISize WAS %d(0x%x)\n",
|
|
|
|
availSpace.ISize(lineWM), availSpace.ISize(lineWM));
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if ((availSpace.BSize(lineWM) != NS_UNCONSTRAINEDSIZE) &&
|
|
|
|
CRAZY_SIZE(availSpace.BSize(lineWM))) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": UpdateBand: bad caller: BSize WAS %d(0x%x)\n",
|
|
|
|
availSpace.BSize(lineWM), availSpace.BSize(lineWM));
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
#endif
|
1999-03-24 18:41:49 +03:00
|
|
|
|
|
|
|
// Compute the difference between last times width and the new width
|
2014-03-12 00:23:50 +04:00
|
|
|
NS_WARN_IF_FALSE(mRootSpan->mIEnd != NS_UNCONSTRAINEDSIZE &&
|
2014-10-22 02:16:13 +04:00
|
|
|
availSpace.ISize(lineWM) != NS_UNCONSTRAINEDSIZE,
|
|
|
|
"have unconstrained inline size; this should only result "
|
|
|
|
"from very large sizes, not attempts at intrinsic width "
|
2009-10-29 06:22:28 +03:00
|
|
|
"calculation");
|
2014-03-12 00:23:50 +04:00
|
|
|
// The root span's mIStart moves to aICoord
|
|
|
|
nscoord deltaICoord = availSpace.IStart(lineWM) - mRootSpan->mIStart;
|
2014-10-22 02:16:13 +04:00
|
|
|
// The inline size of all spans changes by this much (the root span's
|
|
|
|
// mIEnd moves to aICoord + aISize, its new inline size is aISize)
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord deltaISize = availSpace.ISize(lineWM) -
|
|
|
|
(mRootSpan->mIEnd - mRootSpan->mIStart);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": UpdateBand: %d,%d,%d,%d deltaISize=%d deltaICoord=%d\n",
|
2014-10-22 02:16:13 +04:00
|
|
|
availSpace.IStart(lineWM), availSpace.BStart(lineWM),
|
|
|
|
availSpace.ISize(lineWM), availSpace.BSize(lineWM),
|
|
|
|
deltaISize, deltaICoord);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
2008-06-11 03:53:22 +04:00
|
|
|
// Update the root span position
|
2014-03-12 00:23:50 +04:00
|
|
|
mRootSpan->mIStart += deltaICoord;
|
|
|
|
mRootSpan->mIEnd += deltaICoord;
|
|
|
|
mRootSpan->mICoord += deltaICoord;
|
1999-03-24 18:41:49 +03:00
|
|
|
|
2008-06-11 03:53:22 +04:00
|
|
|
// Now update the right edges of the open spans to account for any
|
|
|
|
// change in available space width
|
|
|
|
for (PerSpanData* psd = mCurrentSpan; psd; psd = psd->mParent) {
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mIEnd += deltaISize;
|
2011-10-17 18:59:28 +04:00
|
|
|
psd->mContainsFloat = true;
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(" span %p: oldIEnd=%d newIEnd=%d\n",
|
|
|
|
psd, psd->mIEnd - deltaISize, psd->mIEnd);
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
|
|
|
}
|
2008-06-11 03:53:22 +04:00
|
|
|
NS_ASSERTION(mRootSpan->mContainsFloat &&
|
2014-03-12 00:23:50 +04:00
|
|
|
mRootSpan->mIStart == availSpace.IStart(lineWM) &&
|
|
|
|
mRootSpan->mIEnd == availSpace.IEnd(lineWM),
|
2008-06-11 03:53:22 +04:00
|
|
|
"root span was updated incorrectly?");
|
|
|
|
|
|
|
|
// Update frame bounds
|
|
|
|
// Note: Only adjust the outermost frames (the ones that are direct
|
|
|
|
// children of the block), not the ones in the child spans. The reason
|
|
|
|
// is simple: the frames in the spans have coordinates local to their
|
|
|
|
// parent therefore they are moved when their parent span is moved.
|
2014-03-12 00:23:50 +04:00
|
|
|
if (deltaICoord != 0) {
|
2008-06-11 03:53:22 +04:00
|
|
|
for (PerFrameData* pfd = mRootSpan->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.IStart(lineWM) += deltaICoord;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
2008-06-11 03:53:22 +04:00
|
|
|
|
2014-06-17 16:19:38 +04:00
|
|
|
mBStartEdge = availSpace.BStart(lineWM);
|
2012-09-28 05:56:40 +04:00
|
|
|
mImpactedByFloats = true;
|
2008-06-11 03:53:22 +04:00
|
|
|
|
2012-09-28 05:56:40 +04:00
|
|
|
mLastFloatWasLetterFrame = nsGkAtoms::letterFrame == aFloatFrame->GetType();
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
2013-02-23 14:38:15 +04:00
|
|
|
nsLineLayout::PerSpanData*
|
|
|
|
nsLineLayout::NewPerSpanData()
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2015-01-13 07:14:46 +03:00
|
|
|
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
|
|
|
|
PerSpanData* psd = outerLineLayout->mSpanFreeList;
|
2013-02-23 14:38:15 +04:00
|
|
|
if (!psd) {
|
2004-07-15 21:50:34 +04:00
|
|
|
void *mem;
|
2014-10-21 19:42:24 +04:00
|
|
|
size_t sz = sizeof(PerSpanData);
|
2015-01-13 07:14:46 +03:00
|
|
|
PL_ARENA_ALLOCATE(mem, &outerLineLayout->mArena, sz);
|
2013-02-23 14:38:15 +04:00
|
|
|
if (!mem) {
|
2014-10-21 19:42:24 +04:00
|
|
|
NS_ABORT_OOM(sz);
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
2007-07-08 11:08:04 +04:00
|
|
|
psd = reinterpret_cast<PerSpanData*>(mem);
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-01-13 07:14:46 +03:00
|
|
|
outerLineLayout->mSpanFreeList = psd->mNextFreeSpan;
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
2012-07-30 18:20:58 +04:00
|
|
|
psd->mParent = nullptr;
|
|
|
|
psd->mFrame = nullptr;
|
|
|
|
psd->mFirstFrame = nullptr;
|
|
|
|
psd->mLastFrame = nullptr;
|
2011-10-17 18:59:28 +04:00
|
|
|
psd->mContainsFloat = false;
|
|
|
|
psd->mHasNonemptyContent = false;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
#ifdef DEBUG
|
2015-01-13 07:14:46 +03:00
|
|
|
outerLineLayout->mSpansAllocated++;
|
2002-08-14 17:00:16 +04:00
|
|
|
#endif
|
2013-02-23 14:38:15 +04:00
|
|
|
return psd;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-07-22 22:38:57 +04:00
|
|
|
|
2013-02-23 14:38:15 +04:00
|
|
|
void
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
|
|
|
const nsHTMLReflowState* aSpanReflowState,
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord aIStart, nscoord aIEnd,
|
2011-08-03 22:30:58 +04:00
|
|
|
nscoord* aBaseline)
|
1998-10-20 04:23:11 +04:00
|
|
|
{
|
2014-03-12 00:23:50 +04:00
|
|
|
NS_ASSERTION(aIEnd != NS_UNCONSTRAINEDSIZE,
|
2007-12-13 00:51:00 +03:00
|
|
|
"should no longer be using unconstrained sizes");
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth+1);
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": BeginSpan leftEdge=%d rightEdge=%d\n", aIStart, aIEnd);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
2013-02-23 14:38:15 +04:00
|
|
|
PerSpanData* psd = NewPerSpanData();
|
|
|
|
// Link up span frame's pfd to point to its child span data
|
|
|
|
PerFrameData* pfd = mCurrentSpan->mLastFrame;
|
|
|
|
NS_ASSERTION(pfd->mFrame == aFrame, "huh?");
|
|
|
|
pfd->mSpan = psd;
|
|
|
|
|
|
|
|
// Init new span
|
|
|
|
psd->mFrame = pfd;
|
|
|
|
psd->mParent = mCurrentSpan;
|
|
|
|
psd->mReflowState = aSpanReflowState;
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mIStart = aIStart;
|
|
|
|
psd->mICoord = aIStart;
|
|
|
|
psd->mIEnd = aIEnd;
|
2013-02-23 14:38:15 +04:00
|
|
|
psd->mBaseline = aBaseline;
|
|
|
|
|
2013-03-25 07:50:59 +04:00
|
|
|
nsIFrame* frame = aSpanReflowState->frame;
|
2014-12-22 07:17:55 +03:00
|
|
|
psd->mNoWrap = !frame->StyleText()->WhiteSpaceCanWrap(frame) ||
|
2015-02-18 07:20:02 +03:00
|
|
|
mSuppressLineWrap ||
|
2015-03-11 02:28:21 +03:00
|
|
|
frame->StyleContext()->ShouldSuppressLineBreak();
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mWritingMode = aSpanReflowState->GetWritingMode();
|
2013-02-23 14:38:15 +04:00
|
|
|
|
|
|
|
// Switch to new span
|
|
|
|
mCurrentSpan = psd;
|
|
|
|
mSpanDepth++;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2007-12-13 00:51:18 +03:00
|
|
|
nscoord
|
|
|
|
nsLineLayout::EndSpan(nsIFrame* aFrame)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span");
|
|
|
|
#ifdef NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": EndSpan width=%d\n", mCurrentSpan->mICoord - mCurrentSpan->mIStart);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord iSizeResult = psd->mLastFrame ? (psd->mICoord - psd->mIStart) : 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
mSpanDepth--;
|
2012-07-30 18:20:58 +04:00
|
|
|
mCurrentSpan->mReflowState = nullptr; // no longer valid so null it out!
|
1999-03-19 00:03:25 +03:00
|
|
|
mCurrentSpan = mCurrentSpan->mParent;
|
2014-03-12 00:23:50 +04:00
|
|
|
return iSizeResult;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2014-12-10 01:49:45 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::AttachFrameToBaseLineLayout(PerFrameData* aFrame)
|
|
|
|
{
|
2015-01-13 07:14:46 +03:00
|
|
|
NS_PRECONDITION(mBaseLineLayout,
|
2014-12-10 01:49:45 +03:00
|
|
|
"This method must not be called in a base line layout.");
|
|
|
|
|
|
|
|
PerFrameData* baseFrame = mBaseLineLayout->LastFrame();
|
|
|
|
MOZ_ASSERT(aFrame && baseFrame);
|
2014-12-23 02:22:26 +03:00
|
|
|
MOZ_ASSERT(!aFrame->mIsLinkedToBase,
|
2014-12-10 01:49:45 +03:00
|
|
|
"The frame must not have been linked with the base");
|
2015-01-13 07:14:46 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsIAtom* baseType = baseFrame->mFrame->GetType();
|
|
|
|
nsIAtom* annotationType = aFrame->mFrame->GetType();
|
|
|
|
MOZ_ASSERT((baseType == nsGkAtoms::rubyBaseContainerFrame &&
|
|
|
|
annotationType == nsGkAtoms::rubyTextContainerFrame) ||
|
|
|
|
(baseType == nsGkAtoms::rubyBaseFrame &&
|
|
|
|
annotationType == nsGkAtoms::rubyTextFrame));
|
|
|
|
#endif
|
2014-12-10 01:49:45 +03:00
|
|
|
|
|
|
|
aFrame->mNextAnnotation = baseFrame->mNextAnnotation;
|
|
|
|
baseFrame->mNextAnnotation = aFrame;
|
2014-12-23 02:22:26 +03:00
|
|
|
aFrame->mIsLinkedToBase = true;
|
2014-12-10 01:49:45 +03:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::GetCurrentSpanCount() const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t count = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd = mRootSpan->mFirstFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
1999-03-19 00:03:25 +03:00
|
|
|
count++;
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsLineLayout::SplitLineTo(int32_t aNewCount)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_PUSHING
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("SplitLineTo %d (current count=%d); before:\n", aNewCount,
|
1999-03-19 00:03:25 +03:00
|
|
|
GetCurrentSpanCount());
|
|
|
|
DumpPerSpanData(mRootSpan, 1);
|
|
|
|
#endif
|
|
|
|
PerSpanData* psd = mRootSpan;
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
1999-03-19 00:03:25 +03:00
|
|
|
if (--aNewCount == 0) {
|
2002-08-14 17:00:16 +04:00
|
|
|
// Truncate list at pfd (we keep pfd, but anything following is freed)
|
|
|
|
PerFrameData* next = pfd->mNext;
|
2012-07-30 18:20:58 +04:00
|
|
|
pfd->mNext = nullptr;
|
1999-03-19 00:03:25 +03:00
|
|
|
psd->mLastFrame = pfd;
|
|
|
|
|
2014-12-09 01:14:49 +03:00
|
|
|
// Now unlink all of the frames following pfd
|
|
|
|
UnlinkFrame(next);
|
1998-10-20 04:23:11 +04:00
|
|
|
break;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
pfd = pfd->mNext;
|
1998-10-20 04:23:11 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_PUSHING
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("SplitLineTo %d (current count=%d); after:\n", aNewCount,
|
1999-03-19 00:03:25 +03:00
|
|
|
GetCurrentSpanCount());
|
|
|
|
DumpPerSpanData(mRootSpan, 1);
|
|
|
|
#endif
|
|
|
|
}
|
1998-10-20 04:23:11 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::PushFrame(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
NS_ASSERTION(psd->mLastFrame->mFrame == aFrame, "pushing non-last frame");
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_PUSHING
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("PushFrame %p, before:\n", psd);
|
1999-03-19 00:03:25 +03:00
|
|
|
DumpPerSpanData(psd, 1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Take the last frame off of the span's frame list
|
|
|
|
PerFrameData* pfd = psd->mLastFrame;
|
|
|
|
if (pfd == psd->mFirstFrame) {
|
|
|
|
// We are pushing away the only frame...empty the list
|
2012-07-30 18:20:58 +04:00
|
|
|
psd->mFirstFrame = nullptr;
|
|
|
|
psd->mLastFrame = nullptr;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
PerFrameData* prevFrame = pfd->mPrev;
|
2012-07-30 18:20:58 +04:00
|
|
|
prevFrame->mNext = nullptr;
|
1999-03-19 00:03:25 +03:00
|
|
|
psd->mLastFrame = prevFrame;
|
|
|
|
}
|
|
|
|
|
2014-12-09 01:14:49 +03:00
|
|
|
// Now unlink the frame
|
|
|
|
MOZ_ASSERT(!pfd->mNext);
|
|
|
|
UnlinkFrame(pfd);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef NOISY_PUSHING
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("PushFrame: %p after:\n", psd);
|
1999-03-19 00:03:25 +03:00
|
|
|
DumpPerSpanData(psd, 1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2002-08-14 17:00:16 +04:00
|
|
|
void
|
2014-12-09 01:14:49 +03:00
|
|
|
nsLineLayout::UnlinkFrame(PerFrameData* pfd)
|
2002-08-14 17:00:16 +04:00
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
2014-12-09 01:14:49 +03:00
|
|
|
PerFrameData* next = pfd->mNext;
|
2014-12-23 02:22:26 +03:00
|
|
|
if (pfd->mIsLinkedToBase) {
|
2014-12-09 01:30:23 +03:00
|
|
|
// This frame is linked to a ruby base, and should not be freed
|
|
|
|
// now. Just unlink it from the span. It will be freed when its
|
|
|
|
// base frame gets unlinked.
|
|
|
|
pfd->mNext = pfd->mPrev = nullptr;
|
|
|
|
pfd = next;
|
|
|
|
continue;
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
2014-12-09 01:30:23 +03:00
|
|
|
|
|
|
|
// It is a ruby base frame. If there are any annotations
|
|
|
|
// linked to this frame, free them first.
|
|
|
|
PerFrameData* annotationPFD = pfd->mNextAnnotation;
|
|
|
|
while (annotationPFD) {
|
|
|
|
PerFrameData* nextAnnotation = annotationPFD->mNextAnnotation;
|
|
|
|
MOZ_ASSERT(annotationPFD->mNext == nullptr &&
|
|
|
|
annotationPFD->mPrev == nullptr,
|
|
|
|
"PFD in annotations should have been unlinked.");
|
|
|
|
FreeFrame(annotationPFD);
|
|
|
|
annotationPFD = nextAnnotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeFrame(pfd);
|
2002-08-14 17:00:16 +04:00
|
|
|
pfd = next;
|
|
|
|
}
|
2014-12-09 01:14:49 +03:00
|
|
|
}
|
|
|
|
|
2014-12-09 01:30:23 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::FreeFrame(PerFrameData* pfd)
|
|
|
|
{
|
|
|
|
if (nullptr != pfd->mSpan) {
|
|
|
|
FreeSpan(pfd->mSpan);
|
|
|
|
}
|
2015-01-13 07:14:46 +03:00
|
|
|
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
|
|
|
|
pfd->mNext = outerLineLayout->mFrameFreeList;
|
|
|
|
outerLineLayout->mFrameFreeList = pfd;
|
2014-12-09 01:30:23 +03:00
|
|
|
#ifdef DEBUG
|
2015-01-13 07:14:46 +03:00
|
|
|
outerLineLayout->mFramesFreed++;
|
2014-12-09 01:30:23 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-12-09 01:14:49 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::FreeSpan(PerSpanData* psd)
|
|
|
|
{
|
|
|
|
// Unlink its frames
|
|
|
|
UnlinkFrame(psd->mFirstFrame);
|
2002-08-14 17:00:16 +04:00
|
|
|
|
2015-01-13 07:14:46 +03:00
|
|
|
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
|
2005-11-21 01:05:24 +03:00
|
|
|
// Now put the span on the free list since it's free too
|
2015-01-13 07:14:46 +03:00
|
|
|
psd->mNextFreeSpan = outerLineLayout->mSpanFreeList;
|
|
|
|
outerLineLayout->mSpanFreeList = psd;
|
2002-08-14 17:00:16 +04:00
|
|
|
#ifdef DEBUG
|
2015-01-13 07:14:46 +03:00
|
|
|
outerLineLayout->mSpansFreed++;
|
2002-08-14 17:00:16 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2014-03-12 00:23:50 +04:00
|
|
|
nsLineLayout::IsZeroBSize()
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
2014-03-12 00:23:50 +04:00
|
|
|
if (0 != pfd->mBounds.BSize(psd->mWritingMode)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2013-02-23 14:38:15 +04:00
|
|
|
nsLineLayout::PerFrameData*
|
2014-03-12 00:23:50 +04:00
|
|
|
nsLineLayout::NewPerFrameData(nsIFrame* aFrame)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2015-01-13 07:14:46 +03:00
|
|
|
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
|
|
|
|
PerFrameData* pfd = outerLineLayout->mFrameFreeList;
|
2013-02-23 14:38:15 +04:00
|
|
|
if (!pfd) {
|
2004-07-15 21:50:34 +04:00
|
|
|
void *mem;
|
2014-10-21 19:42:24 +04:00
|
|
|
size_t sz = sizeof(PerFrameData);
|
2015-01-13 07:14:46 +03:00
|
|
|
PL_ARENA_ALLOCATE(mem, &outerLineLayout->mArena, sz);
|
2013-02-23 14:38:15 +04:00
|
|
|
if (!mem) {
|
2014-10-21 19:42:24 +04:00
|
|
|
NS_ABORT_OOM(sz);
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
2007-07-08 11:08:04 +04:00
|
|
|
pfd = reinterpret_cast<PerFrameData*>(mem);
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-01-13 07:14:46 +03:00
|
|
|
outerLineLayout->mFrameFreeList = pfd->mNext;
|
2002-08-14 17:00:16 +04:00
|
|
|
}
|
2012-07-30 18:20:58 +04:00
|
|
|
pfd->mSpan = nullptr;
|
|
|
|
pfd->mNext = nullptr;
|
|
|
|
pfd->mPrev = nullptr;
|
2014-12-06 02:57:12 +03:00
|
|
|
pfd->mNextAnnotation = nullptr;
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mFrame = aFrame;
|
|
|
|
|
2014-12-23 02:22:26 +03:00
|
|
|
// all flags default to false
|
|
|
|
pfd->mRelativePos = false;
|
|
|
|
pfd->mIsTextFrame = false;
|
|
|
|
pfd->mIsNonEmptyTextFrame = false;
|
|
|
|
pfd->mIsNonWhitespaceTextFrame = false;
|
|
|
|
pfd->mIsLetterFrame = false;
|
|
|
|
pfd->mRecomputeOverflow = false;
|
|
|
|
pfd->mIsBullet = false;
|
|
|
|
pfd->mSkipWhenTrimmingWhitespace = false;
|
|
|
|
pfd->mIsEmpty = false;
|
|
|
|
pfd->mIsLinkedToBase = false;
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode frameWM = aFrame->GetWritingMode();
|
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
|
|
|
pfd->mBounds = LogicalRect(lineWM);
|
2015-01-13 12:04:41 +03:00
|
|
|
pfd->mOverflowAreas.Clear();
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin = LogicalMargin(lineWM);
|
|
|
|
pfd->mBorderPadding = LogicalMargin(lineWM);
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mOffsets = LogicalMargin(frameWM);
|
2000-02-02 10:38:23 +03:00
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
pfd->mJustificationInfo = JustificationInfo();
|
|
|
|
pfd->mJustificationAssignment = JustificationAssignment();
|
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
#ifdef DEBUG
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = 0xFF;
|
2015-01-13 07:14:46 +03:00
|
|
|
outerLineLayout->mFramesAllocated++;
|
1999-03-22 23:45:09 +03:00
|
|
|
#endif
|
2013-02-23 14:38:15 +04:00
|
|
|
return pfd;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
1999-03-24 18:41:49 +03:00
|
|
|
nsLineLayout::LineIsBreakable() const
|
|
|
|
{
|
2008-06-14 12:28:07 +04:00
|
|
|
// XXX mTotalPlacedFrames should go away and we should just use
|
2012-09-28 05:56:40 +04:00
|
|
|
// mLineIsEmpty here instead
|
|
|
|
if ((0 != mTotalPlacedFrames) || mImpactedByFloats) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
|
|
|
|
2007-01-27 21:40:26 +03:00
|
|
|
// Checks all four sides for percentage units. This means it should
|
|
|
|
// only be used for things (margin, padding) where percentages on top
|
|
|
|
// and bottom depend on the *width* just like percentages on left and
|
|
|
|
// right.
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool
|
2007-01-27 21:40:26 +03:00
|
|
|
HasPercentageUnitSide(const nsStyleSides& aSides)
|
|
|
|
{
|
|
|
|
NS_FOR_CSS_SIDES(side) {
|
2010-08-31 20:05:12 +04:00
|
|
|
if (aSides.Get(side).HasPercent())
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool
|
2007-01-27 21:40:26 +03:00
|
|
|
IsPercentageAware(const nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aFrame, "null frame is not allowed");
|
|
|
|
|
|
|
|
nsIAtom *fType = aFrame->GetType();
|
|
|
|
if (fType == nsGkAtoms::textFrame) {
|
|
|
|
// None of these things can ever be true for text frames.
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Some of these things don't apply to non-replaced inline frames
|
2011-04-30 03:02:33 +04:00
|
|
|
// (that is, fType == nsGkAtoms::inlineFrame), but we won't bother making
|
2007-01-27 21:40:26 +03:00
|
|
|
// things unnecessarily complicated, since they'll probably be set
|
|
|
|
// quite rarely.
|
|
|
|
|
2013-02-17 01:51:02 +04:00
|
|
|
const nsStyleMargin* margin = aFrame->StyleMargin();
|
2007-01-27 21:40:26 +03:00
|
|
|
if (HasPercentageUnitSide(margin->mMargin)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
2013-02-17 01:51:02 +04:00
|
|
|
const nsStylePadding* padding = aFrame->StylePadding();
|
2007-01-27 21:40:26 +03:00
|
|
|
if (HasPercentageUnitSide(padding->mPadding)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Note that borders can't be aware of percentages
|
|
|
|
|
2013-02-17 01:51:02 +04:00
|
|
|
const nsStylePosition* pos = aFrame->StylePosition();
|
2007-01-27 21:40:26 +03:00
|
|
|
|
2010-08-11 23:32:52 +04:00
|
|
|
if ((pos->WidthDependsOnContainer() &&
|
|
|
|
pos->mWidth.GetUnit() != eStyleUnit_Auto) ||
|
|
|
|
pos->MaxWidthDependsOnContainer() ||
|
|
|
|
pos->MinWidthDependsOnContainer() ||
|
2010-08-25 14:17:56 +04:00
|
|
|
pos->OffsetHasPercent(NS_SIDE_RIGHT) ||
|
|
|
|
pos->OffsetHasPercent(NS_SIDE_LEFT)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (eStyleUnit_Auto == pos->mWidth.GetUnit()) {
|
|
|
|
// We need to check for frames that shrink-wrap when they're auto
|
|
|
|
// width.
|
2013-02-17 01:51:02 +04:00
|
|
|
const nsStyleDisplay* disp = aFrame->StyleDisplay();
|
2007-01-27 21:40:26 +03:00
|
|
|
if (disp->mDisplay == NS_STYLE_DISPLAY_INLINE_BLOCK ||
|
|
|
|
disp->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE ||
|
|
|
|
fType == nsGkAtoms::HTMLButtonControlFrame ||
|
|
|
|
fType == nsGkAtoms::gfxButtonControlFrame ||
|
2007-02-28 06:04:38 +03:00
|
|
|
fType == nsGkAtoms::fieldSetFrame ||
|
|
|
|
fType == nsGkAtoms::comboboxDisplayFrame) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
2007-11-18 15:09:03 +03:00
|
|
|
|
2011-06-13 05:52:32 +04:00
|
|
|
// Per CSS 2.1, section 10.3.2:
|
|
|
|
// If 'height' and 'width' both have computed values of 'auto' and
|
|
|
|
// the element has an intrinsic ratio but no intrinsic height or
|
|
|
|
// width and the containing block's width does not itself depend
|
|
|
|
// on the replaced element's width, then the used value of 'width'
|
|
|
|
// is calculated from the constraint equation used for
|
|
|
|
// block-level, non-replaced elements in normal flow.
|
|
|
|
nsIFrame *f = const_cast<nsIFrame*>(aFrame);
|
|
|
|
if (f->GetIntrinsicRatio() != nsSize(0, 0) &&
|
|
|
|
// Some percents are treated like 'auto', so check != coord
|
|
|
|
pos->mHeight.GetUnit() != eStyleUnit_Coord) {
|
2013-10-01 01:26:04 +04:00
|
|
|
const IntrinsicSize &intrinsicSize = f->GetIntrinsicSize();
|
2011-06-13 05:52:32 +04:00
|
|
|
if (intrinsicSize.width.GetUnit() == eStyleUnit_None &&
|
|
|
|
intrinsicSize.height.GetUnit() == eStyleUnit_None) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2011-06-13 05:52:32 +04:00
|
|
|
}
|
2007-11-18 15:09:03 +03:00
|
|
|
}
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2007-01-27 21:40:26 +03:00
|
|
|
}
|
|
|
|
|
2014-05-13 04:47:53 +04:00
|
|
|
void
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
1999-10-29 18:33:26 +04:00
|
|
|
nsReflowStatus& aReflowStatus,
|
2000-01-03 07:32:13 +03:00
|
|
|
nsHTMLReflowMetrics* aMetrics,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool& aPushedFrame)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2000-01-03 07:32:13 +03:00
|
|
|
// Initialize OUT parameter
|
2011-10-17 18:59:28 +04:00
|
|
|
aPushedFrame = false;
|
2000-01-03 07:32:13 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
PerFrameData* pfd = NewPerFrameData(aFrame);
|
1999-03-19 00:03:25 +03:00
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
psd->AppendFrame(pfd);
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p: Begin ReflowFrame pfd=%p ", psd, pfd);
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
2014-06-18 20:55:00 +04:00
|
|
|
if (mCurrentSpan == mRootSpan) {
|
|
|
|
pfd->mFrame->Properties().Remove(nsIFrame::LineBaselineOffset());
|
|
|
|
} else {
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool hasLineOffset;
|
|
|
|
pfd->mFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &hasLineOffset);
|
|
|
|
NS_ASSERTION(!hasLineOffset, "LineBaselineOffset was set but was not expected");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
mJustificationInfo = JustificationInfo();
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Stash copies of some of the computed state away for later
|
2014-03-12 00:23:50 +04:00
|
|
|
// (block-direction alignment, for example)
|
|
|
|
WritingMode frameWM = aFrame->GetWritingMode();
|
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2014-06-17 18:41:33 +04:00
|
|
|
// NOTE: While the inline direction coordinate remains relative to the
|
|
|
|
// parent span, the block direction coordinate is fixed at the top
|
|
|
|
// edge for the line. During VerticalAlignFrames we will repair this
|
|
|
|
// so that the block direction coordinate is properly set and relative
|
|
|
|
// to the appropriate span.
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.IStart(lineWM) = psd->mICoord;
|
|
|
|
pfd->mBounds.BStart(lineWM) = mBStartEdge;
|
2001-12-11 05:45:44 +03:00
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
// We want to guarantee that we always make progress when
|
|
|
|
// formatting. Therefore, if the object being placed on the line is
|
2006-10-19 05:47:47 +04:00
|
|
|
// too big for the line, but it is the only thing on the line and is not
|
|
|
|
// impacted by a float, then we go ahead and place it anyway. (If the line
|
|
|
|
// is impacted by one or more floats, then it is safe to break because
|
|
|
|
// we can move the line down below float(s).)
|
1999-03-22 23:45:09 +03:00
|
|
|
//
|
1999-03-19 00:03:25 +03:00
|
|
|
// Capture this state *before* we reflow the frame in case it clears
|
|
|
|
// the state out. We need to know how to treat the current frame
|
|
|
|
// when breaking.
|
2012-09-28 05:56:40 +04:00
|
|
|
bool notSafeToBreak = LineIsEmpty() && !mImpactedByFloats;
|
2010-08-25 22:54:47 +04:00
|
|
|
|
|
|
|
// Figure out whether we're talking about a textframe here
|
|
|
|
nsIAtom* frameType = aFrame->GetType();
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isText = frameType == nsGkAtoms::textFrame;
|
2006-10-19 05:47:47 +04:00
|
|
|
|
2010-08-25 22:54:47 +04:00
|
|
|
// Inline-ish and text-ish things don't compute their width;
|
|
|
|
// everything else does. We need to give them an available width that
|
|
|
|
// reflects the space left on the line.
|
2015-06-16 02:36:11 +03:00
|
|
|
LAYOUT_WARN_IF_FALSE(psd->mIEnd != NS_UNCONSTRAINEDSIZE,
|
2015-06-16 02:36:12 +03:00
|
|
|
"have unconstrained width; this should only result from "
|
|
|
|
"very large sizes, not attempts at intrinsic width "
|
|
|
|
"calculation");
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord availableSpaceOnLine = psd->mIEnd - psd->mICoord;
|
2010-08-25 22:54:47 +04:00
|
|
|
|
|
|
|
// Setup reflow state for reflowing the frame
|
2011-04-29 02:48:52 +04:00
|
|
|
Maybe<nsHTMLReflowState> reflowStateHolder;
|
2010-08-25 22:54:47 +04:00
|
|
|
if (!isText) {
|
2014-07-10 13:11:33 +04:00
|
|
|
// Compute the available size for the frame. This available width
|
|
|
|
// includes room for the side margins.
|
|
|
|
// For now, set the available block-size to unconstrained always.
|
2014-07-24 12:28:46 +04:00
|
|
|
LogicalSize availSize = mBlockReflowState->ComputedSize(frameWM);
|
|
|
|
availSize.BSize(frameWM) = NS_UNCONSTRAINEDSIZE;
|
2014-08-14 02:42:15 +04:00
|
|
|
reflowStateHolder.emplace(mPresContext, *psd->mReflowState,
|
|
|
|
aFrame, availSize);
|
|
|
|
nsHTMLReflowState& reflowState = *reflowStateHolder;
|
2010-08-25 22:54:47 +04:00
|
|
|
reflowState.mLineLayout = this;
|
2012-09-28 05:56:40 +04:00
|
|
|
reflowState.mFlags.mIsTopOfPage = mIsTopOfPage;
|
2014-10-16 12:40:20 +04:00
|
|
|
if (reflowState.ComputedISize() == NS_UNCONSTRAINEDSIZE) {
|
|
|
|
reflowState.AvailableISize() = availableSpaceOnLine;
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode stateWM = reflowState.GetWritingMode();
|
|
|
|
pfd->mMargin =
|
2014-11-13 11:58:02 +03:00
|
|
|
reflowState.ComputedLogicalMargin().ConvertTo(lineWM, stateWM);
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBorderPadding =
|
2014-11-13 11:58:02 +03:00
|
|
|
reflowState.ComputedLogicalBorderPadding().ConvertTo(lineWM, stateWM);
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mRelativePos =
|
|
|
|
reflowState.mStyleDisplay->IsRelativelyPositionedStyle();
|
|
|
|
if (pfd->mRelativePos) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mOffsets =
|
|
|
|
reflowState.ComputedLogicalOffsets().ConvertTo(frameWM, stateWM);
|
2010-08-25 22:54:47 +04:00
|
|
|
}
|
|
|
|
|
2014-05-20 18:04:54 +04:00
|
|
|
// Calculate whether the the frame should have a start margin and
|
|
|
|
// subtract the margin from the available width if necessary.
|
|
|
|
// The margin will be applied to the starting inline coordinates of
|
|
|
|
// the frame in CanPlaceFrame() after reflowing the frame.
|
|
|
|
AllowForStartMargin(pfd, reflowState);
|
2010-08-25 22:54:47 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
// if isText(), no need to propagate NS_FRAME_IS_DIRTY from the parent,
|
|
|
|
// because reflow doesn't look at the dirty bits on the frame being reflowed.
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2011-02-16 00:34:52 +03:00
|
|
|
// See if this frame depends on the width of its containing block. If
|
|
|
|
// so, disable resize reflow optimizations for the line. (Note that,
|
|
|
|
// to be conservative, we do this if we *try* to fit a frame on a
|
|
|
|
// line, even if we don't succeed.) (Note also that we can only make
|
|
|
|
// this IsPercentageAware check *after* we've constructed our
|
|
|
|
// nsHTMLReflowState, because that construction may be what forces aFrame
|
|
|
|
// to lazily initialize its (possibly-percent-valued) intrinsic size.)
|
2012-09-28 05:56:40 +04:00
|
|
|
if (mGotLineBox && IsPercentageAware(aFrame)) {
|
2011-02-16 00:34:52 +03:00
|
|
|
mLineBox->DisableResizeReflowOptimization();
|
|
|
|
}
|
|
|
|
|
2015-03-30 01:38:40 +03:00
|
|
|
// Note that we don't bother positioning the frame yet, because we're probably
|
|
|
|
// going to end up moving it when we do the block-direction alignment.
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2010-08-11 23:32:53 +04:00
|
|
|
// Adjust spacemanager coordinate system for the frame.
|
2014-03-12 00:23:50 +04:00
|
|
|
nsHTMLReflowMetrics metrics(lineWM);
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef DEBUG
|
2014-07-24 12:30:07 +04:00
|
|
|
metrics.ISize(lineWM) = nscoord(0xdeadbeef);
|
|
|
|
metrics.BSize(lineWM) = nscoord(0xdeadbeef);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
2015-07-16 12:07:57 +03:00
|
|
|
nscoord tI = pfd->mBounds.LineLeft(lineWM, ContainerSize());
|
2015-03-22 12:44:48 +03:00
|
|
|
nscoord tB = pfd->mBounds.BStart(lineWM);
|
|
|
|
mFloatManager->Translate(tI, tB);
|
1999-12-10 21:41:43 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t savedOptionalBreakOffset;
|
2008-07-24 11:16:18 +04:00
|
|
|
gfxBreakPriority savedOptionalBreakPriority;
|
2014-11-14 08:41:14 +03:00
|
|
|
nsIFrame* savedOptionalBreakFrame =
|
2008-07-24 11:16:18 +04:00
|
|
|
GetLastOptionalBreakPosition(&savedOptionalBreakOffset,
|
|
|
|
&savedOptionalBreakPriority);
|
2002-05-29 02:50:43 +04:00
|
|
|
|
2010-08-25 22:54:47 +04:00
|
|
|
if (!isText) {
|
2014-08-14 02:42:15 +04:00
|
|
|
aFrame->Reflow(mPresContext, metrics, *reflowStateHolder, aReflowStatus);
|
2010-08-25 22:54:47 +04:00
|
|
|
} else {
|
|
|
|
static_cast<nsTextFrame*>(aFrame)->
|
|
|
|
ReflowText(*this, availableSpaceOnLine, psd->mReflowState->rendContext,
|
2013-04-14 14:11:07 +04:00
|
|
|
metrics, aReflowStatus);
|
2001-04-20 01:54:35 +04:00
|
|
|
}
|
2014-11-10 04:25:17 +03:00
|
|
|
|
|
|
|
pfd->mJustificationInfo = mJustificationInfo;
|
2014-12-15 01:57:36 +03:00
|
|
|
mJustificationInfo = JustificationInfo();
|
2000-04-17 18:40:46 +04:00
|
|
|
|
2008-02-14 12:08:33 +03:00
|
|
|
// See if the frame is a placeholderFrame and if it is process
|
|
|
|
// the float. At the same time, check if the frame has any non-collapsed-away
|
|
|
|
// content.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool placedFloat = false;
|
|
|
|
bool isEmpty;
|
2008-03-12 03:46:18 +03:00
|
|
|
if (!frameType) {
|
|
|
|
isEmpty = pfd->mFrame->IsEmpty();
|
|
|
|
} else {
|
2006-12-26 20:47:52 +03:00
|
|
|
if (nsGkAtoms::placeholderFrame == frameType) {
|
2011-10-17 18:59:28 +04:00
|
|
|
isEmpty = true;
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mSkipWhenTrimmingWhitespace = true;
|
2004-09-13 17:35:46 +04:00
|
|
|
nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
|
1999-04-25 21:01:07 +04:00
|
|
|
if (outOfFlowFrame) {
|
2014-10-22 02:16:11 +04:00
|
|
|
// Add mTrimmableISize to the available width since if the line ends
|
2008-08-12 13:29:35 +04:00
|
|
|
// here, the width of the inline content will be reduced by
|
2014-10-22 02:16:11 +04:00
|
|
|
// mTrimmableISize.
|
|
|
|
nscoord availableISize = psd->mIEnd - (psd->mICoord - mTrimmableISize);
|
2008-08-12 13:29:35 +04:00
|
|
|
if (psd->mNoWrap) {
|
|
|
|
// If we place floats after inline content where there's
|
|
|
|
// no break opportunity, we don't know how much additional
|
|
|
|
// width is required for the non-breaking content after the float,
|
|
|
|
// so we can't know whether the float plus that content will fit
|
|
|
|
// on the line. So for now, don't place floats after inline
|
|
|
|
// content where there's no break opportunity. This is incorrect
|
|
|
|
// but hopefully rare. Fixing it will require significant
|
|
|
|
// restructuring of line layout.
|
|
|
|
// We might as well allow zero-width floats to be placed, though.
|
2014-10-22 02:16:11 +04:00
|
|
|
availableISize = 0;
|
2008-08-12 13:29:35 +04:00
|
|
|
}
|
2015-01-13 07:14:46 +03:00
|
|
|
placedFloat = GetOutermostLineLayout()->
|
|
|
|
AddFloat(outOfFlowFrame, availableISize);
|
2007-12-05 11:15:15 +03:00
|
|
|
NS_ASSERTION(!(outOfFlowFrame->GetType() == nsGkAtoms::letterFrame &&
|
|
|
|
GetFirstLetterStyleOK()),
|
|
|
|
"FirstLetterStyle set on line with floating first letter");
|
1999-04-23 19:15:53 +04:00
|
|
|
}
|
|
|
|
}
|
2010-08-25 22:54:47 +04:00
|
|
|
else if (isText) {
|
2005-11-21 01:05:24 +03:00
|
|
|
// Note non-empty text-frames for inline frame compatibility hackery
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mIsTextFrame = true;
|
2008-02-14 12:08:33 +03:00
|
|
|
nsTextFrame* textFrame = static_cast<nsTextFrame*>(pfd->mFrame);
|
2008-03-12 03:46:18 +03:00
|
|
|
isEmpty = !textFrame->HasNoncollapsedCharacters();
|
|
|
|
if (!isEmpty) {
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mIsNonEmptyTextFrame = true;
|
2008-02-14 12:08:33 +03:00
|
|
|
nsIContent* content = textFrame->GetContent();
|
2004-05-08 00:55:17 +04:00
|
|
|
|
2006-07-19 08:36:36 +04:00
|
|
|
const nsTextFragment* frag = content->GetText();
|
|
|
|
if (frag) {
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mIsNonWhitespaceTextFrame = !content->TextIsOnlyWhitespace();
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
1999-09-03 07:47:49 +04:00
|
|
|
}
|
|
|
|
}
|
2006-12-26 20:47:52 +03:00
|
|
|
else if (nsGkAtoms::brFrame == frameType) {
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mSkipWhenTrimmingWhitespace = true;
|
2011-10-17 18:59:28 +04:00
|
|
|
isEmpty = false;
|
2008-02-14 12:08:33 +03:00
|
|
|
} else {
|
|
|
|
if (nsGkAtoms::letterFrame==frameType) {
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mIsLetterFrame = true;
|
2008-02-14 12:08:33 +03:00
|
|
|
}
|
2008-03-12 03:46:18 +03:00
|
|
|
if (pfd->mSpan) {
|
2010-03-10 03:14:14 +03:00
|
|
|
isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
|
2008-03-12 03:46:18 +03:00
|
|
|
} else {
|
|
|
|
isEmpty = pfd->mFrame->IsEmpty();
|
2008-02-14 12:08:33 +03:00
|
|
|
}
|
2006-04-21 05:31:35 +04:00
|
|
|
}
|
1999-04-23 19:15:53 +04:00
|
|
|
}
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mIsEmpty = isEmpty;
|
1999-04-23 19:15:53 +04:00
|
|
|
|
2015-03-22 12:44:48 +03:00
|
|
|
mFloatManager->Translate(-tI, -tB);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2014-07-24 12:30:07 +04:00
|
|
|
NS_ASSERTION(metrics.ISize(lineWM) >= 0, "bad inline size");
|
|
|
|
NS_ASSERTION(metrics.BSize(lineWM) >= 0,"bad block size");
|
|
|
|
if (metrics.ISize(lineWM) < 0) {
|
|
|
|
metrics.ISize(lineWM) = 0;
|
|
|
|
}
|
|
|
|
if (metrics.BSize(lineWM) < 0) {
|
|
|
|
metrics.BSize(lineWM) = 0;
|
|
|
|
}
|
2000-10-30 07:11:59 +03:00
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
// Note: break-before means ignore the reflow metrics since the
|
|
|
|
// frame will be reflowed another time.
|
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
2014-07-24 12:30:07 +04:00
|
|
|
if (CRAZY_SIZE(metrics.ISize(lineWM)) ||
|
|
|
|
CRAZY_SIZE(metrics.BSize(lineWM))) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLineLayout: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2013-12-27 21:59:52 +04:00
|
|
|
printf(" metrics=%d,%d!\n", metrics.Width(), metrics.Height());
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
2013-12-27 21:59:52 +04:00
|
|
|
if ((metrics.Width() == nscoord(0xdeadbeef)) ||
|
|
|
|
(metrics.Height() == nscoord(0xdeadbeef))) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsLineLayout: ");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2013-12-27 21:59:52 +04:00
|
|
|
printf(" didn't set w/h %d,%d!\n", metrics.Width(), metrics.Height());
|
1999-03-24 18:41:49 +03:00
|
|
|
}
|
1999-03-20 02:07:17 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
2004-08-25 17:03:28 +04:00
|
|
|
// Unlike with non-inline reflow, the overflow area here does *not*
|
|
|
|
// include the accumulation of the frame's bounds and its inline
|
|
|
|
// descendants' bounds. Nor does it include the outline area; it's
|
|
|
|
// just the union of the bounds of any absolute children. That is
|
|
|
|
// added in later by nsLineLayout::ReflowInlineFrames.
|
2010-10-07 08:25:45 +04:00
|
|
|
pfd->mOverflowAreas = metrics.mOverflowAreas;
|
2004-08-25 17:03:28 +04:00
|
|
|
|
2014-06-05 13:39:36 +04:00
|
|
|
pfd->mBounds.ISize(lineWM) = metrics.ISize(lineWM);
|
|
|
|
pfd->mBounds.BSize(lineWM) = metrics.BSize(lineWM);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2003-07-23 04:14:16 +04:00
|
|
|
// Size the frame, but |RelativePositionFrames| will size the view.
|
2015-07-16 12:07:57 +03:00
|
|
|
aFrame->SetRect(lineWM, pfd->mBounds, ContainerSizeForSpan(psd));
|
1999-03-19 00:03:25 +03:00
|
|
|
|
1999-11-19 18:33:29 +03:00
|
|
|
// Tell the frame that we're done reflowing it
|
2010-08-25 22:54:47 +04:00
|
|
|
aFrame->DidReflow(mPresContext,
|
2014-08-14 02:42:15 +04:00
|
|
|
isText ? nullptr : reflowStateHolder.ptr(),
|
2012-11-14 10:47:33 +04:00
|
|
|
nsDidReflowStatus::FINISHED);
|
1999-11-19 18:33:29 +03:00
|
|
|
|
1999-10-29 18:33:26 +04:00
|
|
|
if (aMetrics) {
|
|
|
|
*aMetrics = metrics;
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
|
|
|
// If frame is complete and has a next-in-flow, we need to delete
|
|
|
|
// them now. Do not do this when a break-before is signaled because
|
|
|
|
// the frame is going to get reflowed again (and may end up wanting
|
|
|
|
// a next-in-flow where it ends up).
|
|
|
|
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
|
2004-09-14 06:28:03 +04:00
|
|
|
nsIFrame* kidNextInFlow = aFrame->GetNextInFlow();
|
2012-07-30 18:20:58 +04:00
|
|
|
if (nullptr != kidNextInFlow) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// Remove all of the childs next-in-flows. Make sure that we ask
|
|
|
|
// the right parent to do the removal (it's possible that the
|
|
|
|
// parent is not this because we are executing pullup code)
|
2014-05-25 02:20:40 +04:00
|
|
|
kidNextInFlow->GetParent()->
|
|
|
|
DeleteNextInFlowChild(kidNextInFlow, true);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-19 05:47:47 +04:00
|
|
|
// Check whether this frame breaks up text runs. All frames break up text
|
|
|
|
// runs (hence return false here) except for text frames and inline containers.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool continuingTextRun = aFrame->CanContinueTextRun();
|
2006-10-19 05:47:47 +04:00
|
|
|
|
2014-10-22 02:16:11 +04:00
|
|
|
// Clear any residual mTrimmableISize if this isn't a text frame
|
2014-12-23 02:22:26 +03:00
|
|
|
if (!continuingTextRun && !pfd->mSkipWhenTrimmingWhitespace) {
|
2014-10-22 02:16:11 +04:00
|
|
|
mTrimmableISize = 0;
|
2008-02-08 02:00:37 +03:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// See if we can place the frame. If we can't fit it, then we
|
|
|
|
// return now.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool optionalBreakAfterFits;
|
2010-08-25 22:54:47 +04:00
|
|
|
NS_ASSERTION(isText ||
|
2014-08-14 02:42:15 +04:00
|
|
|
!reflowStateHolder->IsFloating(),
|
2010-08-25 22:54:47 +04:00
|
|
|
"How'd we get a floated inline frame? "
|
|
|
|
"The frame ctor should've dealt with this.");
|
2014-03-12 00:23:50 +04:00
|
|
|
if (CanPlaceFrame(pfd, notSafeToBreak, continuingTextRun,
|
2014-11-14 08:41:14 +03:00
|
|
|
savedOptionalBreakFrame != nullptr, metrics,
|
2007-12-07 12:17:19 +03:00
|
|
|
aReflowStatus, &optionalBreakAfterFits)) {
|
2008-03-12 03:46:18 +03:00
|
|
|
if (!isEmpty) {
|
2011-10-17 18:59:28 +04:00
|
|
|
psd->mHasNonemptyContent = true;
|
2012-09-28 05:56:40 +04:00
|
|
|
mLineIsEmpty = false;
|
2010-03-10 03:14:14 +03:00
|
|
|
if (!pfd->mSpan) {
|
|
|
|
// nonempty leaf content has been placed
|
2012-09-28 05:56:40 +04:00
|
|
|
mLineAtStart = false;
|
2010-03-10 03:14:14 +03:00
|
|
|
}
|
2014-12-13 03:48:30 +03:00
|
|
|
if (nsGkAtoms::rubyFrame == frameType) {
|
|
|
|
mHasRuby = true;
|
2015-02-24 06:46:29 +03:00
|
|
|
SyncAnnotationBounds(pfd);
|
2014-12-13 03:48:30 +03:00
|
|
|
}
|
2008-02-14 13:03:01 +03:00
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Place the frame, updating aBounds with the final size and
|
|
|
|
// location. Then apply the bottom+right margins (as
|
|
|
|
// appropriate) to the frame.
|
|
|
|
PlaceFrame(pfd, metrics);
|
|
|
|
PerSpanData* span = pfd->mSpan;
|
|
|
|
if (span) {
|
|
|
|
// The frame we just finished reflowing is an inline
|
2014-03-12 00:23:50 +04:00
|
|
|
// container. It needs its child frames aligned in the block direction,
|
1999-03-19 00:03:25 +03:00
|
|
|
// so do most of it now.
|
2014-06-17 18:41:33 +04:00
|
|
|
VerticalAlignFrames(span);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2006-10-19 05:47:47 +04:00
|
|
|
|
|
|
|
if (!continuingTextRun) {
|
2008-06-14 12:28:07 +04:00
|
|
|
if (!psd->mNoWrap && (!LineIsEmpty() || placedFloat)) {
|
2006-10-19 05:47:47 +04:00
|
|
|
// record soft break opportunity after this content that can't be
|
|
|
|
// part of a text run. This is not a text frame so we know
|
2012-09-28 10:57:33 +04:00
|
|
|
// that offset INT32_MAX means "after the content".
|
2014-11-14 08:41:14 +03:00
|
|
|
if (NotifyOptionalBreakPosition(aFrame, INT32_MAX,
|
|
|
|
optionalBreakAfterFits,
|
|
|
|
gfxBreakPriority::eNormalBreak)) {
|
2006-10-19 05:47:47 +04:00
|
|
|
// If this returns true then we are being told to actually break here.
|
|
|
|
aReflowStatus = NS_INLINE_LINE_BREAK_AFTER(aReflowStatus);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
PushFrame(aFrame);
|
2011-10-17 18:59:28 +04:00
|
|
|
aPushedFrame = true;
|
2006-10-19 05:47:47 +04:00
|
|
|
// Undo any saved break positions that the frame might have told us about,
|
|
|
|
// since we didn't end up placing it
|
2014-11-14 08:41:14 +03:00
|
|
|
RestoreSavedBreakPosition(savedOptionalBreakFrame,
|
2008-07-24 11:16:18 +04:00
|
|
|
savedOptionalBreakOffset,
|
|
|
|
savedOptionalBreakPriority);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PushFrame(aFrame);
|
|
|
|
}
|
2006-10-19 05:47:47 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
|
|
|
nsFrame::IndentBy(stdout, mSpanDepth);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("End ReflowFrame ");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" status=%x\n", aReflowStatus);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-05-20 18:04:54 +04:00
|
|
|
nsLineLayout::AllowForStartMargin(PerFrameData* pfd,
|
|
|
|
nsHTMLReflowState& aReflowState)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2012-08-02 15:38:49 +04:00
|
|
|
NS_ASSERTION(!aReflowState.IsFloating(),
|
2002-01-31 02:28:56 +03:00
|
|
|
"How'd we get a floated inline frame? "
|
|
|
|
"The frame ctor should've dealt with this.");
|
|
|
|
|
2014-11-13 11:58:02 +03:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2002-01-31 02:28:56 +03:00
|
|
|
|
2009-05-12 06:04:58 +04:00
|
|
|
// Only apply start-margin on the first-in flow for inline frames,
|
2009-09-18 22:00:21 +04:00
|
|
|
// and make sure to not apply it to any inline other than the first
|
2014-02-07 05:45:33 +04:00
|
|
|
// in an ib split. Note that the ib sibling (block-in-inline
|
|
|
|
// sibling) annotations only live on the first continuation, but we
|
|
|
|
// don't want to apply the start margin for later continuations
|
2014-05-05 21:55:54 +04:00
|
|
|
// anyway. For box-decoration-break:clone we apply the start-margin
|
|
|
|
// on all continuations.
|
|
|
|
if ((pfd->mFrame->GetPrevContinuation() ||
|
|
|
|
pfd->mFrame->FrameIsNonFirstInIBSplit()) &&
|
|
|
|
aReflowState.mStyleBorder->mBoxDecorationBreak ==
|
|
|
|
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
|
2003-01-09 17:26:32 +03:00
|
|
|
// Zero this out so that when we compute the max-element-width of
|
2002-01-31 02:28:56 +03:00
|
|
|
// the frame we will properly avoid adding in the starting margin.
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.IStart(lineWM) = 0;
|
2014-05-20 18:04:54 +04:00
|
|
|
} else {
|
2014-10-24 15:24:40 +04:00
|
|
|
NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.AvailableISize(),
|
|
|
|
"have unconstrained inline-size; this should only result "
|
|
|
|
"from very large sizes, not attempts at intrinsic "
|
|
|
|
"inline-size calculation");
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedISize()) {
|
2007-01-27 21:36:57 +03:00
|
|
|
// For inline-ish and text-ish things (which don't compute widths
|
2014-10-24 15:24:40 +04:00
|
|
|
// in the reflow state), adjust available inline-size to account for the
|
2014-03-12 00:23:50 +04:00
|
|
|
// start margin. The end margin will be accounted for when we
|
2007-01-27 21:36:57 +03:00
|
|
|
// finish flowing the frame.
|
2014-11-13 11:58:02 +03:00
|
|
|
WritingMode wm = aReflowState.GetWritingMode();
|
|
|
|
aReflowState.AvailableISize() -=
|
|
|
|
pfd->mMargin.ConvertTo(wm, lineWM).IStart(wm);
|
2006-06-15 12:16:23 +04:00
|
|
|
}
|
2002-01-31 02:28:56 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2007-05-21 07:44:26 +04:00
|
|
|
nscoord
|
2014-03-12 00:23:50 +04:00
|
|
|
nsLineLayout::GetCurrentFrameInlineDistanceFromBlock()
|
2007-05-21 07:44:26 +04:00
|
|
|
{
|
|
|
|
PerSpanData* psd;
|
|
|
|
nscoord x = 0;
|
|
|
|
for (psd = mCurrentSpan; psd; psd = psd->mParent) {
|
2014-03-12 00:23:50 +04:00
|
|
|
x += psd->mICoord;
|
2007-05-21 07:44:26 +04:00
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2015-01-07 04:47:09 +03:00
|
|
|
/**
|
2015-02-17 04:25:18 +03:00
|
|
|
* This method syncs bounds of ruby annotations and ruby annotation
|
|
|
|
* containers from their rect. It is necessary because:
|
|
|
|
* Containers are not part of the line in their levels, which means
|
|
|
|
* their bounds are not set properly before.
|
2015-03-14 08:46:33 +03:00
|
|
|
* Ruby annotations' position may have been changed when reflowing
|
|
|
|
* their containers.
|
2015-01-07 04:47:09 +03:00
|
|
|
*/
|
|
|
|
void
|
2015-02-17 04:25:18 +03:00
|
|
|
nsLineLayout::SyncAnnotationBounds(PerFrameData* aRubyFrame)
|
2015-01-07 04:47:09 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aRubyFrame->mFrame->GetType() == nsGkAtoms::rubyFrame);
|
|
|
|
MOZ_ASSERT(aRubyFrame->mSpan);
|
|
|
|
|
|
|
|
PerSpanData* span = aRubyFrame->mSpan;
|
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
|
|
|
for (PerFrameData* pfd = span->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2015-02-17 04:25:18 +03:00
|
|
|
for (PerFrameData* rtc = pfd->mNextAnnotation;
|
|
|
|
rtc; rtc = rtc->mNextAnnotation) {
|
2015-03-14 08:46:33 +03:00
|
|
|
// When the annotation container is reflowed, the width of the
|
2015-07-16 12:07:57 +03:00
|
|
|
// ruby container is unknown so we use a dummy container size;
|
|
|
|
// in the case of RTL block direction, the final position will be
|
|
|
|
// fixed up later.
|
|
|
|
const nsSize dummyContainerSize;
|
|
|
|
LogicalRect rtcBounds(lineWM, rtc->mFrame->GetRect(),
|
|
|
|
dummyContainerSize);
|
2015-02-17 04:25:18 +03:00
|
|
|
rtc->mBounds = rtcBounds;
|
2015-07-16 12:07:57 +03:00
|
|
|
nsSize rtcSize = rtcBounds.Size(lineWM).GetPhysicalSize(lineWM);
|
2015-02-17 04:25:18 +03:00
|
|
|
for (PerFrameData* rt = rtc->mSpan->mFirstFrame; rt; rt = rt->mNext) {
|
2015-07-16 12:07:57 +03:00
|
|
|
LogicalRect rtBounds = rt->mFrame->GetLogicalRect(lineWM, rtcSize);
|
2015-03-14 08:46:33 +03:00
|
|
|
MOZ_ASSERT(rt->mBounds.Size(lineWM) == rtBounds.Size(lineWM),
|
|
|
|
"Size of the annotation should not have been changed");
|
|
|
|
rt->mBounds.SetOrigin(lineWM, rtBounds.Origin(lineWM));
|
2015-02-17 04:25:18 +03:00
|
|
|
}
|
2015-01-07 04:47:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
/**
|
|
|
|
* See if the frame can be placed now that we know it's desired size.
|
|
|
|
* We can always place the frame if the line is empty. Note that we
|
|
|
|
* know that the reflow-status is not a break-before because if it was
|
|
|
|
* ReflowFrame above would have returned false, preventing this method
|
|
|
|
* from being called. The logic in this method assumes that.
|
|
|
|
*
|
|
|
|
* Note that there is no check against the Y coordinate because we
|
|
|
|
* assume that the caller will take care of that.
|
|
|
|
*/
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aNotSafeToBreak,
|
|
|
|
bool aFrameCanContinueTextRun,
|
|
|
|
bool aCanRollBackBeforeFrame,
|
1999-03-19 00:03:25 +03:00
|
|
|
nsHTMLReflowMetrics& aMetrics,
|
2007-12-07 12:17:19 +03:00
|
|
|
nsReflowStatus& aStatus,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool* aOptionalBreakAfterFits)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
NS_PRECONDITION(pfd && pfd->mFrame, "bad args, null pointers for frame data");
|
2014-03-11 12:22:52 +04:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
*aOptionalBreakAfterFits = true;
|
2014-02-18 08:07:45 +04:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2014-02-18 08:07:45 +04:00
|
|
|
/*
|
|
|
|
* We want to only apply the end margin if we're the last continuation and
|
|
|
|
* either not in an {ib} split or the last inline in it. In all other
|
|
|
|
* cases we want to zero it out. That means zeroing it out if any of these
|
|
|
|
* conditions hold:
|
|
|
|
* 1) The frame is not complete (in this case it will get a next-in-flow)
|
|
|
|
* 2) The frame is complete but has a non-fluid continuation on its
|
|
|
|
* continuation chain. Note that if it has a fluid continuation, that
|
|
|
|
* continuation will get destroyed later, so we don't want to drop the
|
|
|
|
* end-margin in that case.
|
|
|
|
* 3) The frame is in an {ib} split and is not the last part.
|
|
|
|
*
|
|
|
|
* However, none of that applies if this is a letter frame (XXXbz why?)
|
2014-05-05 21:55:54 +04:00
|
|
|
*
|
|
|
|
* For box-decoration-break:clone we apply the end margin on all
|
|
|
|
* continuations (that are not letter frames).
|
2014-02-18 08:07:45 +04:00
|
|
|
*/
|
|
|
|
if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) ||
|
|
|
|
pfd->mFrame->LastInFlow()->GetNextContinuation() ||
|
2014-05-05 21:55:54 +04:00
|
|
|
pfd->mFrame->FrameIsNonLastInIBSplit()) &&
|
2014-12-23 02:22:26 +03:00
|
|
|
!pfd->mIsLetterFrame &&
|
2014-05-05 21:55:54 +04:00
|
|
|
pfd->mFrame->StyleBorder()->mBoxDecorationBreak ==
|
|
|
|
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.IEnd(lineWM) = 0;
|
2014-03-12 00:23:50 +04:00
|
|
|
}
|
2014-05-20 18:04:54 +04:00
|
|
|
|
2014-11-13 11:58:02 +03:00
|
|
|
// Apply the start margin to the frame bounds.
|
|
|
|
nscoord startMargin = pfd->mMargin.IStart(lineWM);
|
|
|
|
nscoord endMargin = pfd->mMargin.IEnd(lineWM);
|
2014-03-12 00:23:50 +04:00
|
|
|
|
2014-05-20 18:04:54 +04:00
|
|
|
pfd->mBounds.IStart(lineWM) += startMargin;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
PerSpanData* psd = mCurrentSpan;
|
|
|
|
if (psd->mNoWrap) {
|
1999-11-02 18:44:57 +03:00
|
|
|
// When wrapping is off, everything fits.
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-03-21 04:14:43 +03:00
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2012-07-30 18:20:58 +04:00
|
|
|
if (nullptr != psd->mFrame) {
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": aNotSafeToBreak=%s frame=", aNotSafeToBreak ? "true" : "false");
|
1999-03-24 18:41:49 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(" frameWidth=%d, margins=%d,%d\n",
|
|
|
|
pfd->mBounds.IEnd(lineWM) + endMargin - psd->mICoord,
|
|
|
|
startMargin, endMargin);
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
// Set outside to true if the result of the reflow leads to the
|
1999-03-19 00:03:25 +03:00
|
|
|
// frame sticking outside of our available area.
|
2014-10-22 02:16:11 +04:00
|
|
|
bool outside = pfd->mBounds.IEnd(lineWM) - mTrimmableISize + endMargin >
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mIEnd;
|
1999-03-21 04:14:43 +03:00
|
|
|
if (!outside) {
|
|
|
|
// If it fits, it fits
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> inside\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
*aOptionalBreakAfterFits = false;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
1999-03-21 04:14:43 +03:00
|
|
|
// When it doesn't fit, check for a few special conditions where we
|
|
|
|
// allow it to fit anyway.
|
2014-03-12 00:23:50 +04:00
|
|
|
if (0 == startMargin + pfd->mBounds.ISize(lineWM) + endMargin) {
|
1999-03-19 00:03:25 +03:00
|
|
|
// Empty frames always fit right where they are
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> empty frame fits\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#ifdef FIX_BUG_50257
|
|
|
|
// another special case: always place a BR
|
2006-12-26 20:47:52 +03:00
|
|
|
if (nsGkAtoms::brFrame == pfd->mFrame->GetType()) {
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> BR frame fits\n");
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
#endif
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
bug 14280
nsTextTransformer.cpp.
I moved where we translate the nbsp to a (ascii 32 space character) until after the i18n routines are called, so they can properly account
for the space as non-breaking and therefore part of the first word in the block.
bug 39901 and 38396
nsHTMLImageLoader.*, nsImageFrame.cpp
I backed out the bad fix for 38396, and put in a new fix where I store a little state in the image loader flags for cases where the image
gets an unconstrained reflow and has %-based width. This does not handle %-based min-width or max-width, that would be a separate
bug that I'll file shortly. But this fixes the vast majority of real cases out there.
bug 18754
nsHRFrame.cpp, quirks.css, nsCSSFrameConstructor.cpp, last part of nsLineLayout.cpp
in quirks mode, I changed HR from a block element to a replaced inline element that acts like a block, using generated content to get
newlines before and after the HR. This isn't ideal, but it gets us backwards compatibility, and ian and dbaron have blessed the approach.
bug 50257
nsLineLayout.cpp
Did a couple of things in here:
* The actual fix is controlled by FIX_BUG_50257 #define symbol. This basically says that an break (BR) will always fit on a line.
A more general solution would probably be to round up to the nearest pixel, and if the thing is less than a pixel make it fit on a
line. This is a wimpier, safer solution.
* I noticed that the way we got the compatibility mode was way out of date, very wasteful. So I fixed that.
* I noticed that there were a bunch of redundant SetFlag calls. Since the flag variable is initialized to 0, setting a flag to 0 on a newly
created object is a waste.
nsBlockFrame.cpp -- just added a comment to some odd looking code, to make sure no one comes along later and breaks it
2000-09-12 01:15:02 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-03-22 23:45:09 +03:00
|
|
|
if (aNotSafeToBreak) {
|
2006-10-19 05:47:47 +04:00
|
|
|
// There are no frames on the line that take up width and the line is
|
|
|
|
// not impacted by floats, so we must allow the current frame to be
|
|
|
|
// placed on the line
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2006-10-19 05:47:47 +04:00
|
|
|
printf(" ==> not-safe and not-impacted fits: ");
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != psd) {
|
2014-03-12 00:23:50 +04:00
|
|
|
printf("<psd=%p x=%d left=%d> ", psd, psd->mICoord, psd->mIStart);
|
2006-10-19 05:47:47 +04:00
|
|
|
psd = psd->mParent;
|
1999-03-21 04:14:43 +03:00
|
|
|
}
|
2006-10-19 05:47:47 +04:00
|
|
|
printf("\n");
|
1999-10-29 18:33:26 +04:00
|
|
|
#endif
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2006-10-19 05:47:47 +04:00
|
|
|
|
1999-11-02 18:44:57 +03:00
|
|
|
// Special check for span frames
|
2003-10-14 01:51:02 +04:00
|
|
|
if (pfd->mSpan && pfd->mSpan->mContainsFloat) {
|
|
|
|
// If the span either directly or indirectly contains a float then
|
1999-11-02 18:44:57 +03:00
|
|
|
// it fits. Why? It's kind of complicated, but here goes:
|
|
|
|
//
|
|
|
|
// 1. CanPlaceFrame is used for all frame placements on a line,
|
|
|
|
// and in a span. This includes recursively placement of frames
|
|
|
|
// inside of spans, and the span itself. Because the logic always
|
|
|
|
// checks for room before proceeding (the code above here), the
|
|
|
|
// only things on a line will be those things that "fit".
|
|
|
|
//
|
2003-10-14 01:51:02 +04:00
|
|
|
// 2. Before a float is placed on a line, the line has to be empty
|
2005-11-21 01:05:24 +03:00
|
|
|
// (otherwise it's a "below current line" float and will be placed
|
1999-11-02 18:44:57 +03:00
|
|
|
// after the line).
|
|
|
|
//
|
2003-10-14 01:51:02 +04:00
|
|
|
// Therefore, if the span directly or indirectly has a float
|
|
|
|
// then it means that at the time of the placement of the float
|
1999-11-02 18:44:57 +03:00
|
|
|
// the line was empty. Because of #1, only the frames that fit can
|
|
|
|
// be added after that point, therefore we can assume that the
|
|
|
|
// current span being placed has fit.
|
|
|
|
//
|
|
|
|
// So how do we get here and have a span that should already fit
|
|
|
|
// and yet doesn't: Simple: span's that have the no-wrap attribute
|
2003-10-14 01:51:02 +04:00
|
|
|
// set on them and contain a float and are placed where they
|
1999-11-02 18:44:57 +03:00
|
|
|
// don't naturally fit.
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-11-02 18:44:57 +03:00
|
|
|
}
|
|
|
|
|
2006-10-19 05:47:47 +04:00
|
|
|
if (aFrameCanContinueTextRun) {
|
2007-11-19 00:36:18 +03:00
|
|
|
// Let it fit, but we reserve the right to roll back.
|
|
|
|
// Note that we usually won't get here because a text frame will break
|
|
|
|
// itself to avoid exceeding the available width.
|
2006-10-19 05:47:47 +04:00
|
|
|
// We'll only get here for text frames that couldn't break early enough.
|
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
|
|
|
printf(" ==> placing overflowing textrun, requesting backup\n");
|
|
|
|
#endif
|
2007-11-19 00:36:18 +03:00
|
|
|
|
|
|
|
// We will want to try backup.
|
2012-09-28 05:56:40 +04:00
|
|
|
mNeedBackup = true;
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2006-10-19 05:47:47 +04:00
|
|
|
}
|
|
|
|
|
1999-03-24 18:41:49 +03:00
|
|
|
#ifdef NOISY_CAN_PLACE_FRAME
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> didn't fit\n");
|
1999-03-24 18:41:49 +03:00
|
|
|
#endif
|
1999-03-21 04:14:43 +03:00
|
|
|
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Place the frame. Update running counters.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
|
|
|
{
|
2014-06-11 13:45:31 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
|
|
|
|
2015-03-03 19:39:45 +03:00
|
|
|
// If the frame's block direction does not match the line's, we can't use
|
|
|
|
// its ascent; instead, treat it as a block with baseline at the block-end
|
|
|
|
// edge (or block-begin in the case of an "inverted" line).
|
|
|
|
if (pfd->mFrame->GetWritingMode().GetBlockDir() != lineWM.GetBlockDir()) {
|
|
|
|
pfd->mAscent = lineWM.IsLineInverted() ? 0 : aMetrics.BSize(lineWM);
|
2014-06-11 13:45:31 +04:00
|
|
|
} else {
|
2015-03-03 19:39:45 +03:00
|
|
|
if (aMetrics.BlockStartAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
|
|
|
|
pfd->mAscent = pfd->mFrame->GetLogicalBaseline(lineWM);
|
|
|
|
} else {
|
|
|
|
pfd->mAscent = aMetrics.BlockStartAscent();
|
|
|
|
}
|
2014-06-11 13:45:31 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Advance to next inline coordinate
|
|
|
|
mCurrentSpan->mICoord = pfd->mBounds.IEnd(lineWM) +
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.IEnd(lineWM);
|
2014-02-18 08:07:45 +04:00
|
|
|
|
|
|
|
// Count the number of non-placeholder frames on the line...
|
|
|
|
if (pfd->mFrame->GetType() == nsGkAtoms::placeholderFrame) {
|
2014-03-12 00:23:50 +04:00
|
|
|
NS_ASSERTION(pfd->mBounds.ISize(lineWM) == 0 &&
|
|
|
|
pfd->mBounds.BSize(lineWM) == 0,
|
2014-02-18 08:07:45 +04:00
|
|
|
"placeholders should have 0 width/height (checking "
|
|
|
|
"placeholders were never counted by the old code in "
|
|
|
|
"this function)");
|
|
|
|
} else {
|
2004-10-19 11:12:55 +04:00
|
|
|
mTotalPlacedFrames++;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2013-02-23 14:38:15 +04:00
|
|
|
void
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
|
|
|
const nsHTMLReflowMetrics& aMetrics)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
2012-09-28 05:56:40 +04:00
|
|
|
NS_ASSERTION(mGotLineBox, "must have line box");
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2009-09-11 14:46:36 +04:00
|
|
|
nsIFrame *blockFrame = mBlockReflowState->frame;
|
|
|
|
NS_ASSERTION(blockFrame->IsFrameOfType(nsIFrame::eBlockFrame),
|
|
|
|
"must be for block");
|
|
|
|
if (!static_cast<nsBlockFrame*>(blockFrame)->BulletIsEmpty()) {
|
2012-09-28 05:56:40 +04:00
|
|
|
mHasBullet = true;
|
2009-09-11 14:46:36 +04:00
|
|
|
mLineBox->SetHasBullet();
|
|
|
|
}
|
2009-08-11 06:48:42 +04:00
|
|
|
|
2014-06-11 13:45:31 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2014-03-12 00:23:50 +04:00
|
|
|
PerFrameData* pfd = NewPerFrameData(aFrame);
|
2013-02-23 14:38:15 +04:00
|
|
|
mRootSpan->AppendFrame(pfd);
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mIsBullet = true;
|
2014-06-11 13:45:31 +04:00
|
|
|
if (aMetrics.BlockStartAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
|
2014-06-17 16:19:38 +04:00
|
|
|
pfd->mAscent = aFrame->GetLogicalBaseline(lineWM);
|
2014-06-11 13:45:31 +04:00
|
|
|
} else {
|
|
|
|
pfd->mAscent = aMetrics.BlockStartAscent();
|
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Note: block-coord value will be updated during block-direction alignment
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mBounds = LogicalRect(lineWM, aFrame->GetRect(), ContainerSize());
|
2013-02-23 14:38:15 +04:00
|
|
|
pfd->mOverflowAreas = aMetrics.mOverflowAreas;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsLineLayout::DumpPerSpanData(PerSpanData* psd, int32_t aIndent)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
nsFrame::IndentBy(stdout, aIndent);
|
2007-07-08 11:08:04 +04:00
|
|
|
printf("%p: left=%d x=%d right=%d\n", static_cast<void*>(psd),
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mIStart, psd->mICoord, psd->mIEnd);
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::IndentBy(stdout, aIndent+1);
|
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
nsRect rect = pfd->mBounds.GetPhysicalRect(psd->mWritingMode,
|
2015-07-16 12:07:57 +03:00
|
|
|
ContainerSize());
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(" %d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
|
1999-03-19 00:03:25 +03:00
|
|
|
if (pfd->mSpan) {
|
|
|
|
DumpPerSpanData(pfd->mSpan, aIndent + 1);
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define VALIGN_OTHER 0
|
|
|
|
#define VALIGN_TOP 1
|
|
|
|
#define VALIGN_BOTTOM 2
|
|
|
|
|
2000-06-05 12:24:18 +04:00
|
|
|
void
|
2014-06-17 18:41:33 +04:00
|
|
|
nsLineLayout::VerticalAlignLine()
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
// Partially place the children of the block frame. The baseline for
|
|
|
|
// this operation is set to zero so that the y coordinates for all
|
|
|
|
// of the placed children will be relative to there.
|
|
|
|
PerSpanData* psd = mRootSpan;
|
2014-06-17 18:41:33 +04:00
|
|
|
VerticalAlignFrames(psd);
|
|
|
|
|
|
|
|
// *** Note that comments here still use the anachronistic term
|
|
|
|
// "line-height" when we really mean "size of the line in the block
|
|
|
|
// direction", "vertical-align" when we really mean "alignment in
|
|
|
|
// the block direction", and "top" and "bottom" when we really mean
|
|
|
|
// "block start" and "block end". This is partly for brevity and
|
|
|
|
// partly to retain the association with the CSS line-height and
|
|
|
|
// vertical-align properties.
|
2014-03-12 00:23:50 +04:00
|
|
|
//
|
1999-03-19 00:03:25 +03:00
|
|
|
// Compute the line-height. The line-height will be the larger of:
|
|
|
|
//
|
2014-03-12 00:23:50 +04:00
|
|
|
// [1] maxBCoord - minBCoord (the distance between the first child's
|
|
|
|
// block-start edge and the last child's block-end edge)
|
1999-03-19 00:03:25 +03:00
|
|
|
//
|
2014-03-12 00:23:50 +04:00
|
|
|
// [2] the maximum logical box block size (since not every frame may have
|
2014-06-17 18:41:33 +04:00
|
|
|
// participated in #1; for example: "top" and "botttom" aligned frames)
|
1999-03-19 00:03:25 +03:00
|
|
|
//
|
2014-03-12 00:23:50 +04:00
|
|
|
// [3] the minimum line height ("line-height" property set on the
|
1999-03-19 00:03:25 +03:00
|
|
|
// block frame)
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord lineBSize = psd->mMaxBCoord - psd->mMinBCoord;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Now that the line-height is computed, we need to know where the
|
2014-03-12 00:23:50 +04:00
|
|
|
// baseline is in the line. Position baseline so that mMinBCoord is just
|
|
|
|
// inside the start of the line box.
|
|
|
|
nscoord baselineBCoord;
|
|
|
|
if (psd->mMinBCoord < 0) {
|
|
|
|
baselineBCoord = mBStartEdge - psd->mMinBCoord;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
baselineBCoord = mBStartEdge;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// It's also possible that the line block-size isn't tall enough because
|
2014-06-17 18:41:33 +04:00
|
|
|
// of "top" and "bottom" aligned elements that were not accounted for in
|
2014-03-12 00:23:50 +04:00
|
|
|
// min/max BCoord.
|
1999-03-19 00:03:25 +03:00
|
|
|
//
|
|
|
|
// The CSS2 spec doesn't really say what happens when to the
|
2014-03-12 00:23:50 +04:00
|
|
|
// baseline in this situations. What we do is if the largest start
|
|
|
|
// aligned box block size is greater than the line block-size then we leave
|
|
|
|
// the baseline alone. If the largest end aligned box is greater
|
|
|
|
// than the line block-size then we slide the baseline forward by the extra
|
1999-03-19 00:03:25 +03:00
|
|
|
// amount.
|
|
|
|
//
|
|
|
|
// Navigator 4 gives precedence to the first top/bottom aligned
|
2014-03-12 00:23:50 +04:00
|
|
|
// object. We just let block end aligned objects win.
|
|
|
|
if (lineBSize < mMaxEndBoxBSize) {
|
|
|
|
// When the line is shorter than the maximum block start aligned box
|
|
|
|
nscoord extra = mMaxEndBoxBSize - lineBSize;
|
|
|
|
baselineBCoord += extra;
|
|
|
|
lineBSize = mMaxEndBoxBSize;
|
|
|
|
}
|
|
|
|
if (lineBSize < mMaxStartBoxBSize) {
|
|
|
|
lineBSize = mMaxStartBoxBSize;
|
|
|
|
}
|
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" [line]==> lineBSize=%d baselineBCoord=%d\n", lineBSize, baselineBCoord);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Now position all of the frames in the root span. We will also
|
2014-06-17 18:41:33 +04:00
|
|
|
// recurse over the child spans and place any frames we find with
|
|
|
|
// vertical-align: top or bottom.
|
1999-03-19 00:03:25 +03:00
|
|
|
// XXX PERFORMANCE: set a bit per-span to avoid the extra work
|
2001-07-04 06:00:05 +04:00
|
|
|
// (propagate it upward too)
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode lineWM = psd->mWritingMode;
|
Bug 300030: Move intrinsic width computation out of nsIFrame::Reflow and into its own methods on nsIFrame. Replace reflow reasons, types, and commands with dirty bits/notifications. Thanks to bzbarsky for almost all of the HTML form controls (mozilla/layout/forms) changes, and many others for help testing and patching. For detailed commit logs, see REFLOW_YYYYMMDD_BRANCH, where YYYYMMDD is one of 20061031, 20060830, 20060603, 20060302, 20060119, 20051011, 20050804, 20050429, 20050315, 20050111, and 20041213.
2006-12-08 08:38:33 +03:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2014-03-12 00:23:50 +04:00
|
|
|
if (pfd->mBlockDirAlign == VALIGN_OTHER) {
|
|
|
|
pfd->mBounds.BStart(lineWM) += baselineBCoord;
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerSize());
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
2014-06-17 18:41:33 +04:00
|
|
|
PlaceTopBottomFrames(psd, -mBStartEdge, lineBSize);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
mFinalLineBSize = lineBSize;
|
2014-12-09 09:47:26 +03:00
|
|
|
if (mGotLineBox) {
|
|
|
|
// Fill in returned line-box and max-element-width data
|
|
|
|
mLineBox->SetBounds(lineWM,
|
|
|
|
psd->mIStart, mBStartEdge,
|
|
|
|
psd->mICoord - psd->mIStart, lineBSize,
|
2015-07-16 12:07:57 +03:00
|
|
|
ContainerSize());
|
2014-12-09 09:47:26 +03:00
|
|
|
|
|
|
|
mLineBox->SetLogicalAscent(baselineBCoord - mBStartEdge);
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2014-12-09 09:47:26 +03:00
|
|
|
printf(
|
|
|
|
" [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d\n",
|
|
|
|
mLineBox->GetBounds().IStart(lineWM), mLineBox->GetBounds().BStart(lineWM),
|
|
|
|
mLineBox->GetBounds().ISize(lineWM), mLineBox->GetBounds().BSize(lineWM),
|
|
|
|
mFinalLineBSize, mLineBox->GetLogicalAscent());
|
2001-07-04 06:00:05 +04:00
|
|
|
#endif
|
2014-12-09 09:47:26 +03:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2014-06-17 18:41:33 +04:00
|
|
|
// Place frames with CSS property vertical-align: top or bottom.
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
2014-06-17 18:41:33 +04:00
|
|
|
nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd,
|
|
|
|
nscoord aDistanceFromStart,
|
|
|
|
nscoord aLineBSize)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2008-06-06 20:26:58 +04:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
1999-03-19 00:03:25 +03:00
|
|
|
PerSpanData* span = pfd->mSpan;
|
1999-03-22 23:45:09 +03:00
|
|
|
#ifdef DEBUG
|
2014-03-12 00:23:50 +04:00
|
|
|
NS_ASSERTION(0xFF != pfd->mBlockDirAlign, "umr");
|
1999-03-22 23:45:09 +03:00
|
|
|
#endif
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2015-07-16 12:07:57 +03:00
|
|
|
nsSize containerSize = ContainerSizeForSpan(psd);
|
2014-03-12 00:23:50 +04:00
|
|
|
switch (pfd->mBlockDirAlign) {
|
1999-03-19 00:03:25 +03:00
|
|
|
case VALIGN_TOP:
|
|
|
|
if (span) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = -aDistanceFromStart - span->mMinBCoord;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) =
|
2014-11-13 11:58:02 +03:00
|
|
|
-aDistanceFromStart + pfd->mMargin.BStart(lineWM);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, containerSize);
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": y=%d dTop=%d [bp.top=%d topLeading=%d]\n",
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM), aDistanceFromStart,
|
2014-11-13 11:58:02 +03:00
|
|
|
span ? pfd->mBorderPadding.BStart(lineWM) : 0,
|
2014-03-12 00:23:50 +04:00
|
|
|
span ? span->mBStartLeading : 0);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case VALIGN_BOTTOM:
|
|
|
|
if (span) {
|
|
|
|
// Compute bottom leading
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) =
|
|
|
|
-aDistanceFromStart + aLineBSize - span->mMaxBCoord;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = -aDistanceFromStart + aLineBSize -
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BEnd(lineWM) - pfd->mBounds.BSize(lineWM);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, containerSize);
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ");
|
1999-03-19 00:03:25 +03:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": y=%d\n", pfd->mBounds.BStart(lineWM));
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (span) {
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord fromStart = aDistanceFromStart + pfd->mBounds.BStart(lineWM);
|
2014-06-17 18:41:33 +04:00
|
|
|
PlaceTopBottomFrames(span, fromStart, aLineBSize);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-11 05:13:09 +04:00
|
|
|
static float
|
2014-03-12 00:23:50 +04:00
|
|
|
GetInflationForBlockDirAlignment(nsIFrame* aFrame,
|
2014-01-11 05:13:09 +04:00
|
|
|
nscoord aInflationMinFontSize)
|
|
|
|
{
|
|
|
|
if (aFrame->IsSVGText()) {
|
|
|
|
const nsIFrame* container =
|
|
|
|
nsLayoutUtils::GetClosestFrameOfType(aFrame, nsGkAtoms::svgTextFrame);
|
|
|
|
NS_ASSERTION(container, "expected to find an ancestor SVGTextFrame");
|
|
|
|
return
|
|
|
|
static_cast<const SVGTextFrame*>(container)->GetFontSizeScaleFactor();
|
|
|
|
}
|
|
|
|
return nsLayoutUtils::FontSizeInflationInner(aFrame, aInflationMinFontSize);
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
#define BLOCKDIR_ALIGN_FRAMES_NO_MINIMUM nscoord_MAX
|
|
|
|
#define BLOCKDIR_ALIGN_FRAMES_NO_MAXIMUM nscoord_MIN
|
2000-02-02 10:38:23 +03:00
|
|
|
|
2014-06-17 18:41:33 +04:00
|
|
|
// Place frames in the block direction within a given span (CSS property
|
|
|
|
// vertical-align) Note: this doesn't place frames with vertical-align:
|
|
|
|
// top or bottom as those have to wait until the entire line box block
|
|
|
|
// size is known. This is called after the span frame has finished being
|
|
|
|
// reflowed so that we know its block size.
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
2014-06-17 18:41:33 +04:00
|
|
|
nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
|
|
|
// Get parent frame info
|
1999-11-02 01:38:17 +03:00
|
|
|
PerFrameData* spanFramePFD = psd->mFrame;
|
|
|
|
nsIFrame* spanFrame = spanFramePFD->mFrame;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Get the parent frame's font for all of the frames in this span
|
2011-08-14 21:08:04 +04:00
|
|
|
nsRefPtr<nsFontMetrics> fm;
|
2011-11-24 06:48:23 +04:00
|
|
|
float inflation =
|
2014-03-12 00:23:50 +04:00
|
|
|
GetInflationForBlockDirAlignment(spanFrame, mInflationMinFontSize);
|
2011-11-24 06:48:23 +04:00
|
|
|
nsLayoutUtils::GetFontMetricsForFrame(spanFrame, getter_AddRefs(fm),
|
|
|
|
inflation);
|
1999-09-10 01:04:37 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool preMode = mStyleText->WhiteSpaceIsSignificant();
|
1999-11-02 01:38:17 +03:00
|
|
|
|
|
|
|
// See if the span is an empty continuation. It's an empty continuation iff:
|
|
|
|
// - it has a prev-in-flow
|
|
|
|
// - it has no next in flow
|
|
|
|
// - it's zero sized
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool emptyContinuation = psd != mRootSpan &&
|
2008-10-16 00:57:27 +04:00
|
|
|
spanFrame->GetPrevInFlow() && !spanFrame->GetNextInFlow() &&
|
2014-03-12 00:23:50 +04:00
|
|
|
spanFramePFD->mBounds.IsZeroSize();
|
1999-11-02 01:38:17 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("[%sSpan]", (psd == mRootSpan)?"Root":"");
|
1999-11-02 01:38:17 +03:00
|
|
|
nsFrame::ListTag(stdout, spanFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": preMode=%s strictMode=%s w/h=%d,%d emptyContinuation=%s",
|
1999-11-02 01:38:17 +03:00
|
|
|
preMode ? "yes" : "no",
|
2007-10-02 06:36:26 +04:00
|
|
|
mPresContext->CompatibilityMode() != eCompatibility_NavQuirks ? "yes" : "no",
|
2014-03-12 00:23:50 +04:00
|
|
|
spanFramePFD->mBounds.ISize(lineWM),
|
|
|
|
spanFramePFD->mBounds.BSize(lineWM),
|
1999-11-02 01:38:17 +03:00
|
|
|
emptyContinuation ? "yes" : "no");
|
|
|
|
if (psd != mRootSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode frameWM = spanFramePFD->mFrame->GetWritingMode();
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" bp=%d,%d,%d,%d margin=%d,%d,%d,%d",
|
2014-11-13 11:58:02 +03:00
|
|
|
spanFramePFD->mBorderPadding.Top(lineWM),
|
|
|
|
spanFramePFD->mBorderPadding.Right(lineWM),
|
|
|
|
spanFramePFD->mBorderPadding.Bottom(lineWM),
|
|
|
|
spanFramePFD->mBorderPadding.Left(lineWM),
|
|
|
|
spanFramePFD->mMargin.Top(lineWM),
|
|
|
|
spanFramePFD->mMargin.Right(lineWM),
|
|
|
|
spanFramePFD->mMargin.Bottom(lineWM),
|
|
|
|
spanFramePFD->mMargin.Left(lineWM));
|
1999-11-02 01:38:17 +03:00
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-11-02 01:38:17 +03:00
|
|
|
#endif
|
|
|
|
|
2015-02-19 12:39:19 +03:00
|
|
|
// Compute the span's zeroEffectiveSpanBox flag. What we are trying
|
1999-11-02 01:38:17 +03:00
|
|
|
// to determine is how we should treat the span: should it act
|
|
|
|
// "normally" according to css2 or should it effectively
|
|
|
|
// "disappear".
|
|
|
|
//
|
2002-06-26 01:16:17 +04:00
|
|
|
// In general, if the document being processed is in full standards
|
|
|
|
// mode then it should act normally (with one exception). The
|
|
|
|
// exception case is when a span is continued and yet the span is
|
|
|
|
// empty (e.g. compressed whitespace). For this kind of span we treat
|
|
|
|
// it as if it were not there so that it doesn't impact the
|
2014-03-12 00:23:50 +04:00
|
|
|
// line block-size.
|
1999-11-02 01:38:17 +03:00
|
|
|
//
|
2002-06-26 01:16:17 +04:00
|
|
|
// In almost standards mode or quirks mode, we should sometimes make
|
|
|
|
// it disappear. The cases that matter are those where the span
|
|
|
|
// contains no real text elements that would provide an ascent and
|
|
|
|
// descent and height. However, if css style elements have been
|
|
|
|
// applied to the span (border/padding/margin) so that it's clear the
|
|
|
|
// document author is intending css2 behavior then we act as if strict
|
|
|
|
// mode is set.
|
1999-11-02 01:38:17 +03:00
|
|
|
//
|
2000-03-16 04:14:57 +03:00
|
|
|
// This code works correctly for preMode, because a blank line
|
|
|
|
// in PRE mode is encoded as a text node with a LF in it, since
|
|
|
|
// text nodes with only whitespace are considered in preMode.
|
2001-10-25 05:08:40 +04:00
|
|
|
//
|
|
|
|
// Much of this logic is shared with the various implementations of
|
|
|
|
// nsIFrame::IsEmpty since they need to duplicate the way it makes
|
|
|
|
// some lines empty. However, nsIFrame::IsEmpty can't be reused here
|
|
|
|
// since this code sets zeroEffectiveSpanBox even when there are
|
|
|
|
// non-empty children.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool zeroEffectiveSpanBox = false;
|
2002-05-16 23:44:20 +04:00
|
|
|
// XXXldb If we really have empty continuations, then all these other
|
|
|
|
// checks don't make sense for them.
|
2004-12-16 04:20:57 +03:00
|
|
|
// XXXldb This should probably just use nsIFrame::IsSelfEmpty, assuming that
|
|
|
|
// it agrees with this code. (If it doesn't agree, it probably should.)
|
2007-10-02 06:36:26 +04:00
|
|
|
if ((emptyContinuation ||
|
|
|
|
mPresContext->CompatibilityMode() != eCompatibility_FullStandards) &&
|
2004-03-10 20:13:39 +03:00
|
|
|
((psd == mRootSpan) ||
|
2014-10-05 10:02:36 +04:00
|
|
|
(spanFramePFD->mBorderPadding.IsAllZero() &&
|
|
|
|
spanFramePFD->mMargin.IsAllZero()))) {
|
2005-11-21 01:05:24 +03:00
|
|
|
// This code handles an issue with compatibility with non-css
|
1999-09-10 01:04:37 +04:00
|
|
|
// conformant browsers. In particular, there are some cases
|
|
|
|
// where the font-size and line-height for a span must be
|
|
|
|
// ignored and instead the span must *act* as if it were zero
|
|
|
|
// sized. In general, if the span contains any non-compressed
|
2000-02-15 07:26:44 +03:00
|
|
|
// text then we don't use this logic.
|
2001-12-24 02:23:41 +03:00
|
|
|
// However, this is not propagated outwards, since (in compatibility
|
2000-02-15 07:26:44 +03:00
|
|
|
// mode) we don't want big line heights for things like
|
|
|
|
// <p><font size="-1">Text</font></p>
|
2002-05-01 04:42:49 +04:00
|
|
|
|
2002-12-19 03:21:07 +03:00
|
|
|
// We shouldn't include any whitespace that collapses, unless we're
|
|
|
|
// preformatted (in which case it shouldn't, but the width=0 test is
|
|
|
|
// perhaps incorrect). This includes whitespace at the beginning of
|
|
|
|
// a line and whitespace preceded (?) by other whitespace.
|
|
|
|
// See bug 134580 and bug 155333.
|
2011-10-17 18:59:28 +04:00
|
|
|
zeroEffectiveSpanBox = true;
|
2002-05-01 04:42:49 +04:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2014-12-23 02:22:26 +03:00
|
|
|
if (pfd->mIsTextFrame &&
|
|
|
|
(pfd->mIsNonWhitespaceTextFrame || preMode ||
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.ISize(mRootSpan->mWritingMode) != 0)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
zeroEffectiveSpanBox = false;
|
1999-09-10 01:04:37 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Setup baselineBCoord, minBCoord, and maxBCoord
|
|
|
|
nscoord baselineBCoord, minBCoord, maxBCoord;
|
1999-03-19 00:03:25 +03:00
|
|
|
if (psd == mRootSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
// Use a zero baselineBCoord since we don't yet know where the baseline
|
1999-03-19 00:03:25 +03:00
|
|
|
// will be (until we know how tall the line is; then we will
|
2014-03-12 00:23:50 +04:00
|
|
|
// know). In addition, use extreme values for the minBCoord and maxBCoord
|
1999-03-19 00:03:25 +03:00
|
|
|
// values so that only the child frames will impact their values
|
|
|
|
// (since these are children of the block, there is no span box to
|
|
|
|
// provide initial values).
|
2014-03-12 00:23:50 +04:00
|
|
|
baselineBCoord = 0;
|
|
|
|
minBCoord = BLOCKDIR_ALIGN_FRAMES_NO_MINIMUM;
|
|
|
|
maxBCoord = BLOCKDIR_ALIGN_FRAMES_NO_MAXIMUM;
|
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("[RootSpan]");
|
1999-11-02 01:38:17 +03:00
|
|
|
nsFrame::ListTag(stdout, spanFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": pass1 valign frames: topEdge=%d minLineBSize=%d zeroEffectiveSpanBox=%s\n",
|
|
|
|
mBStartEdge, mMinLineBSize,
|
1999-09-10 01:04:37 +04:00
|
|
|
zeroEffectiveSpanBox ? "yes" : "no");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
// Compute the logical block size for this span. The logical block size
|
|
|
|
// is based on the "line-height" value, not the font-size. Also
|
2000-02-15 07:26:44 +03:00
|
|
|
// compute the top leading.
|
2011-11-24 06:48:23 +04:00
|
|
|
float inflation =
|
2014-03-12 00:23:50 +04:00
|
|
|
GetInflationForBlockDirAlignment(spanFrame, mInflationMinFontSize);
|
|
|
|
nscoord logicalBSize = nsHTMLReflowState::
|
2014-03-13 07:33:21 +04:00
|
|
|
CalcLineHeight(spanFrame->GetContent(), spanFrame->StyleContext(),
|
2011-11-24 06:48:23 +04:00
|
|
|
mBlockReflowState->ComputedHeight(),
|
|
|
|
inflation);
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord contentBSize = spanFramePFD->mBounds.BSize(lineWM) -
|
2014-11-13 11:58:02 +03:00
|
|
|
spanFramePFD->mBorderPadding.BStartEnd(lineWM);
|
2004-11-17 07:12:02 +03:00
|
|
|
|
|
|
|
// Special-case for a ::first-letter frame, set the line height to
|
2014-03-12 00:23:50 +04:00
|
|
|
// the frame block size if the user has left line-height == normal
|
2014-12-23 02:22:26 +03:00
|
|
|
if (spanFramePFD->mIsLetterFrame &&
|
2008-10-16 00:57:27 +04:00
|
|
|
!spanFrame->GetPrevInFlow() &&
|
2013-02-17 01:51:02 +04:00
|
|
|
spanFrame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal) {
|
2014-03-12 00:23:50 +04:00
|
|
|
logicalBSize = spanFramePFD->mBounds.BSize(lineWM);
|
2004-11-17 07:12:02 +03:00
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord leading = logicalBSize - contentBSize;
|
|
|
|
psd->mBStartLeading = leading / 2;
|
|
|
|
psd->mBEndLeading = leading - psd->mBStartLeading;
|
|
|
|
psd->mLogicalBSize = logicalBSize;
|
2015-01-08 08:02:41 +03:00
|
|
|
if (spanFrame->GetType() == nsGkAtoms::rubyFrame) {
|
|
|
|
// We may need to extend leadings here for ruby annotations as
|
|
|
|
// required by section Line Spacing in the CSS Ruby spec.
|
|
|
|
// See http://dev.w3.org/csswg/css-ruby/#line-height
|
|
|
|
auto rubyFrame = static_cast<nsRubyFrame*>(spanFrame);
|
|
|
|
nscoord startLeading, endLeading;
|
|
|
|
rubyFrame->GetBlockLeadings(startLeading, endLeading);
|
|
|
|
nscoord deltaLeading = startLeading + endLeading - leading;
|
|
|
|
if (deltaLeading > 0) {
|
|
|
|
// If the total leading is not wide enough for ruby annotations,
|
|
|
|
// extend the side which is not enough. If both sides are not
|
|
|
|
// wide enough, replace the leadings with the requested values.
|
|
|
|
if (startLeading < psd->mBStartLeading) {
|
|
|
|
psd->mBEndLeading += deltaLeading;
|
|
|
|
} else if (endLeading < psd->mBEndLeading) {
|
|
|
|
psd->mBStartLeading += deltaLeading;
|
|
|
|
} else {
|
|
|
|
psd->mBStartLeading = startLeading;
|
|
|
|
psd->mBEndLeading = endLeading;
|
|
|
|
}
|
|
|
|
psd->mLogicalBSize += deltaLeading;
|
2015-02-19 12:39:19 +03:00
|
|
|
// We have adjusted the leadings, it is no longer a zero
|
|
|
|
// effective span box.
|
|
|
|
zeroEffectiveSpanBox = false;
|
2015-01-08 08:02:41 +03:00
|
|
|
}
|
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
|
1999-09-10 01:04:37 +04:00
|
|
|
if (zeroEffectiveSpanBox) {
|
2000-02-15 07:26:44 +03:00
|
|
|
// When the span-box is to be ignored, zero out the initial
|
1999-09-10 01:04:37 +04:00
|
|
|
// values so that the span doesn't impact the final line
|
|
|
|
// height. The contents of the span can impact the final line
|
|
|
|
// height.
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
// Note that things are readjusted for this span after its children
|
|
|
|
// are reflowed
|
2014-03-12 00:23:50 +04:00
|
|
|
minBCoord = BLOCKDIR_ALIGN_FRAMES_NO_MINIMUM;
|
|
|
|
maxBCoord = BLOCKDIR_ALIGN_FRAMES_NO_MAXIMUM;
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// The initial values for the min and max block coord values are in the
|
|
|
|
// span's coordinate space, and cover the logical block size of the span.
|
|
|
|
// If there are child frames in this span that stick out of this area
|
|
|
|
// then the minBCoord and maxBCoord are updated by the amount of logical
|
|
|
|
// blockSize that is outside this range.
|
2014-11-13 11:58:02 +03:00
|
|
|
minBCoord = spanFramePFD->mBorderPadding.BStart(lineWM) -
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mBStartLeading;
|
|
|
|
maxBCoord = minBCoord + psd->mLogicalBSize;
|
1999-05-04 00:54:11 +04:00
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
// This is the distance from the top edge of the parents visual
|
|
|
|
// box to the baseline. The span already computed this for us,
|
|
|
|
// so just use it.
|
2014-03-12 00:23:50 +04:00
|
|
|
*psd->mBaseline = baselineBCoord = spanFramePFD->mAscent;
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("[%sSpan]", (psd == mRootSpan)?"Root":"");
|
1999-11-02 01:38:17 +03:00
|
|
|
nsFrame::ListTag(stdout, spanFrame);
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(": baseLine=%d logicalBSize=%d topLeading=%d h=%d bp=%d,%d zeroEffectiveSpanBox=%s\n",
|
|
|
|
baselineBCoord, psd->mLogicalBSize, psd->mBStartLeading,
|
|
|
|
spanFramePFD->mBounds.BSize(lineWM),
|
2014-11-13 11:58:02 +03:00
|
|
|
spanFramePFD->mBorderPadding.Top(lineWM),
|
|
|
|
spanFramePFD->mBorderPadding.Bottom(lineWM),
|
1999-09-10 01:04:37 +04:00
|
|
|
zeroEffectiveSpanBox ? "yes" : "no");
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord maxStartBoxBSize = 0;
|
|
|
|
nscoord maxEndBoxBSize = 0;
|
1999-03-19 00:03:25 +03:00
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
1999-03-19 00:03:25 +03:00
|
|
|
nsIFrame* frame = pfd->mFrame;
|
|
|
|
|
2006-11-02 02:02:18 +03:00
|
|
|
// sanity check (see bug 105168, non-reproducible crashes from null frame)
|
2001-11-29 03:10:31 +03:00
|
|
|
NS_ASSERTION(frame, "null frame in PerFrameData - something is very very bad");
|
|
|
|
if (!frame) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Compute the logical block size of the frame
|
|
|
|
nscoord logicalBSize;
|
1999-03-19 00:03:25 +03:00
|
|
|
PerSpanData* frameSpan = pfd->mSpan;
|
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
// For span frames the logical-block-size and start-leading were
|
1999-03-19 00:03:25 +03:00
|
|
|
// pre-computed when the span was reflowed.
|
2014-03-12 00:23:50 +04:00
|
|
|
logicalBSize = frameSpan->mLogicalBSize;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
// For other elements the logical block size is the same as the
|
|
|
|
// frame's block size plus its margins.
|
|
|
|
logicalBSize = pfd->mBounds.BSize(lineWM) +
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BStartEnd(lineWM);
|
2014-03-12 00:23:50 +04:00
|
|
|
if (logicalBSize < 0 &&
|
2013-11-12 22:38:29 +04:00
|
|
|
mPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mAscent -= logicalBSize;
|
|
|
|
logicalBSize = 0;
|
2013-11-12 22:38:29 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Get vertical-align property ("vertical-align" is the CSS name for
|
|
|
|
// block-direction align)
|
2010-08-31 20:05:12 +04:00
|
|
|
const nsStyleCoord& verticalAlign =
|
2013-02-17 01:51:02 +04:00
|
|
|
frame->StyleTextReset()->mVerticalAlign;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint8_t verticalAlignEnum = frame->VerticalAlignEnum();
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [frame]");
|
1999-09-10 01:04:37 +04:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2012-08-02 15:38:48 +04:00
|
|
|
printf(": verticalAlignUnit=%d (enum == %d",
|
2011-10-18 21:44:43 +04:00
|
|
|
verticalAlign.GetUnit(),
|
2010-08-31 20:05:12 +04:00
|
|
|
((eStyleUnit_Enumerated == verticalAlign.GetUnit())
|
|
|
|
? verticalAlign.GetIntValue()
|
1999-09-10 01:04:37 +04:00
|
|
|
: -1));
|
2012-08-02 15:38:48 +04:00
|
|
|
if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) {
|
|
|
|
printf(", after SVG dominant-baseline conversion == %d",
|
|
|
|
verticalAlignEnum);
|
|
|
|
}
|
|
|
|
printf(")\n");
|
1999-09-10 01:04:37 +04:00
|
|
|
#endif
|
|
|
|
|
2012-08-02 15:38:48 +04:00
|
|
|
if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) {
|
2014-11-13 15:58:30 +03:00
|
|
|
if (lineWM.IsVertical()) {
|
|
|
|
if (verticalAlignEnum == NS_STYLE_VERTICAL_ALIGN_MIDDLE) {
|
|
|
|
// For vertical writing mode where the dominant baseline is centered
|
|
|
|
// (i.e. text-orientation is not sideways-*), we remap 'middle' to
|
|
|
|
// 'middle-with-baseline' so that images align sensibly with the
|
|
|
|
// center-baseline-aligned text.
|
|
|
|
if (!lineWM.IsSideways()) {
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE;
|
|
|
|
}
|
|
|
|
} else if (lineWM.IsLineInverted()) {
|
|
|
|
// Swap the meanings of top and bottom when line is inverted
|
|
|
|
// relative to block direction.
|
|
|
|
switch (verticalAlignEnum) {
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TOP:
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_BOTTOM;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_TOP;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
|
|
|
|
break;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2014-11-13 15:58:30 +03:00
|
|
|
}
|
2010-08-31 20:05:12 +04:00
|
|
|
|
2014-11-13 15:58:30 +03:00
|
|
|
// baseline coord that may be adjusted for script offset
|
|
|
|
nscoord revisedBaselineBCoord = baselineBCoord;
|
|
|
|
|
|
|
|
// For superscript and subscript, raise or lower the baseline of the box
|
|
|
|
// to the proper offset of the parent's box, then proceed as for BASELINE
|
|
|
|
if (verticalAlignEnum == NS_STYLE_VERTICAL_ALIGN_SUB ||
|
|
|
|
verticalAlignEnum == NS_STYLE_VERTICAL_ALIGN_SUPER) {
|
|
|
|
revisedBaselineBCoord += lineWM.FlowRelativeToLineRelativeFactor() *
|
|
|
|
(verticalAlignEnum == NS_STYLE_VERTICAL_ALIGN_SUB
|
|
|
|
? fm->SubscriptOffset() : -fm->SuperscriptOffset());
|
|
|
|
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_BASELINE;
|
|
|
|
}
|
2010-08-31 20:05:12 +04:00
|
|
|
|
2014-11-13 15:58:30 +03:00
|
|
|
switch (verticalAlignEnum) {
|
|
|
|
default:
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BASELINE:
|
|
|
|
if (lineWM.IsVertical() && !lineWM.IsSideways()) {
|
|
|
|
if (frameSpan) {
|
|
|
|
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord -
|
|
|
|
pfd->mBounds.BSize(lineWM)/2;
|
|
|
|
} else {
|
|
|
|
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord -
|
|
|
|
logicalBSize/2 +
|
|
|
|
pfd->mMargin.BStart(lineWM);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord - pfd->mAscent;
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_OTHER;
|
2010-08-31 20:05:12 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TOP:
|
|
|
|
{
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_TOP;
|
|
|
|
nscoord subtreeBSize = logicalBSize;
|
2010-08-31 20:05:12 +04:00
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
subtreeBSize = frameSpan->mMaxBCoord - frameSpan->mMinBCoord;
|
|
|
|
NS_ASSERTION(subtreeBSize >= logicalBSize,
|
|
|
|
"unexpected subtree block size");
|
2008-06-06 20:26:58 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (subtreeBSize > maxStartBoxBSize) {
|
|
|
|
maxStartBoxBSize = subtreeBSize;
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2010-08-31 20:05:12 +04:00
|
|
|
case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
|
|
|
|
{
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_BOTTOM;
|
|
|
|
nscoord subtreeBSize = logicalBSize;
|
2010-08-31 20:05:12 +04:00
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
subtreeBSize = frameSpan->mMaxBCoord - frameSpan->mMinBCoord;
|
|
|
|
NS_ASSERTION(subtreeBSize >= logicalBSize,
|
|
|
|
"unexpected subtree block size");
|
2008-06-06 20:26:58 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (subtreeBSize > maxEndBoxBSize) {
|
|
|
|
maxEndBoxBSize = subtreeBSize;
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2010-08-31 20:05:12 +04:00
|
|
|
case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
|
|
|
|
{
|
|
|
|
// Align the midpoint of the frame with 1/2 the parents
|
|
|
|
// x-height above the baseline.
|
2014-11-13 15:58:30 +03:00
|
|
|
nscoord parentXHeight =
|
|
|
|
lineWM.FlowRelativeToLineRelativeFactor() * fm->XHeight();
|
2010-08-31 20:05:12 +04:00
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord -
|
|
|
|
(parentXHeight + pfd->mBounds.BSize(lineWM))/2;
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord -
|
|
|
|
(parentXHeight + logicalBSize)/2 +
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BStart(lineWM);
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_OTHER;
|
2010-08-31 20:05:12 +04:00
|
|
|
break;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2010-08-31 20:05:12 +04:00
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
|
|
|
|
{
|
|
|
|
// The top of the logical box is aligned with the top of
|
|
|
|
// the parent element's text.
|
2014-06-17 16:19:38 +04:00
|
|
|
// XXX For vertical text we will need a new API to get the logical
|
|
|
|
// max-ascent here
|
2014-11-13 15:58:30 +03:00
|
|
|
nscoord parentAscent =
|
|
|
|
lineWM.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent();
|
2010-08-31 20:05:12 +04:00
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord - parentAscent -
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mBorderPadding.BStart(lineWM) + frameSpan->mBStartLeading;
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord - parentAscent +
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BStart(lineWM);
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_OTHER;
|
2010-08-31 20:05:12 +04:00
|
|
|
break;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2010-08-31 20:05:12 +04:00
|
|
|
case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
|
|
|
|
{
|
|
|
|
// The bottom of the logical box is aligned with the
|
|
|
|
// bottom of the parent elements text.
|
2014-11-13 15:58:30 +03:00
|
|
|
nscoord parentDescent =
|
|
|
|
lineWM.IsLineInverted() ? fm->MaxAscent() : fm->MaxDescent();
|
2010-08-31 20:05:12 +04:00
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord + parentDescent -
|
2014-03-24 13:23:12 +04:00
|
|
|
pfd->mBounds.BSize(lineWM) +
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mBorderPadding.BEnd(lineWM) -
|
2014-03-12 00:23:50 +04:00
|
|
|
frameSpan->mBEndLeading;
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord + parentDescent -
|
|
|
|
pfd->mBounds.BSize(lineWM) -
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BEnd(lineWM);
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_OTHER;
|
2010-08-31 20:05:12 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE:
|
|
|
|
{
|
|
|
|
// Align the midpoint of the frame with the baseline of the parent.
|
|
|
|
if (frameSpan) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord -
|
|
|
|
pfd->mBounds.BSize(lineWM)/2;
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) = baselineBCoord - logicalBSize/2 +
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BStart(lineWM);
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_OTHER;
|
2010-08-31 20:05:12 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We have either a coord, a percent, or a calc().
|
|
|
|
nscoord pctBasis = 0;
|
|
|
|
if (verticalAlign.HasPercent()) {
|
|
|
|
// Percentages are like lengths, except treated as a percentage
|
2014-03-12 00:23:50 +04:00
|
|
|
// of the elements line block size value.
|
2011-11-24 06:48:23 +04:00
|
|
|
float inflation =
|
2014-03-12 00:23:50 +04:00
|
|
|
GetInflationForBlockDirAlignment(frame, mInflationMinFontSize);
|
2014-03-13 07:33:21 +04:00
|
|
|
pctBasis = nsHTMLReflowState::CalcLineHeight(frame->GetContent(),
|
2014-03-12 00:23:50 +04:00
|
|
|
frame->StyleContext(), mBlockReflowState->ComputedBSize(),
|
2011-11-24 06:48:23 +04:00
|
|
|
inflation);
|
2010-08-31 20:05:12 +04:00
|
|
|
}
|
|
|
|
nscoord offset =
|
|
|
|
nsRuleNode::ComputeCoordPercentCalc(verticalAlign, pctBasis);
|
|
|
|
// According to the CSS2 spec (10.8.1), a positive value
|
|
|
|
// "raises" the box by the given distance while a negative value
|
|
|
|
// "lowers" the box by the given distance (with zero being the
|
|
|
|
// baseline). Since Y coordinates increase towards the bottom of
|
2015-03-03 15:25:17 +03:00
|
|
|
// the screen we reverse the sign, unless the line orientation is
|
|
|
|
// inverted relative to block direction.
|
|
|
|
nscoord revisedBaselineBCoord = baselineBCoord - offset *
|
|
|
|
lineWM.FlowRelativeToLineRelativeFactor();
|
2015-03-26 15:34:57 +03:00
|
|
|
if (lineWM.IsVertical() && !lineWM.IsSideways()) {
|
|
|
|
// If we're using a dominant center baseline, we align with the center
|
|
|
|
// of the frame being placed (bug 1133945).
|
|
|
|
pfd->mBounds.BStart(lineWM) =
|
|
|
|
revisedBaselineBCoord - pfd->mBounds.BSize(lineWM)/2;
|
|
|
|
} else {
|
|
|
|
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord - pfd->mAscent;
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBlockDirAlign = VALIGN_OTHER;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Update minBCoord/maxBCoord for frames that we just placed. Do not factor
|
1999-09-10 01:04:37 +04:00
|
|
|
// text into the equation.
|
2014-03-12 00:23:50 +04:00
|
|
|
if (pfd->mBlockDirAlign == VALIGN_OTHER) {
|
2014-04-01 22:53:29 +04:00
|
|
|
// Text frames do not contribute to the min/max Y values for the
|
|
|
|
// line (instead their parent frame's font-size contributes).
|
2001-09-27 22:34:30 +04:00
|
|
|
// XXXrbs -- relax this restriction because it causes text frames
|
|
|
|
// to jam together when 'font-size-adjust' is enabled
|
|
|
|
// and layout is using dynamic font heights (bug 20394)
|
|
|
|
// -- Note #1: With this code enabled and with the fact that we are not
|
|
|
|
// using Em[Ascent|Descent] as nsDimensions for text metrics in
|
|
|
|
// GFX mean that the discussion in bug 13072 cannot hold.
|
|
|
|
// -- Note #2: We still don't want empty-text frames to interfere.
|
|
|
|
// For example in quirks mode, avoiding empty text frames prevents
|
|
|
|
// "tall" lines around elements like <hr> since the rules of <hr>
|
|
|
|
// in quirks.css have pseudo text contents with LF in them.
|
2014-04-01 22:53:29 +04:00
|
|
|
#if 0
|
2014-12-23 02:22:26 +03:00
|
|
|
if (!pfd->mIsTextFrame) {
|
2014-04-01 22:53:29 +04:00
|
|
|
#else
|
|
|
|
// Only consider non empty text frames when line-height=normal
|
2014-12-23 02:22:26 +03:00
|
|
|
bool canUpdate = !pfd->mIsTextFrame;
|
|
|
|
if (!canUpdate && pfd->mIsNonWhitespaceTextFrame) {
|
2007-05-11 10:02:31 +04:00
|
|
|
canUpdate =
|
2013-02-17 01:51:02 +04:00
|
|
|
frame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal;
|
2001-09-27 22:34:30 +04:00
|
|
|
}
|
|
|
|
if (canUpdate) {
|
2014-04-01 22:53:29 +04:00
|
|
|
#endif
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord blockStart, blockEnd;
|
1999-09-10 01:04:37 +04:00
|
|
|
if (frameSpan) {
|
|
|
|
// For spans that were are now placing, use their position
|
|
|
|
// plus their already computed min-Y and max-Y values for
|
2014-03-12 00:23:50 +04:00
|
|
|
// computing blockStart and blockEnd.
|
|
|
|
blockStart = pfd->mBounds.BStart(lineWM) + frameSpan->mMinBCoord;
|
|
|
|
blockEnd = pfd->mBounds.BStart(lineWM) + frameSpan->mMaxBCoord;
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
blockStart = pfd->mBounds.BStart(lineWM) -
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mMargin.BStart(lineWM);
|
2014-03-12 00:23:50 +04:00
|
|
|
blockEnd = blockStart + logicalBSize;
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
2002-08-11 22:00:07 +04:00
|
|
|
if (!preMode &&
|
2007-10-02 06:36:26 +04:00
|
|
|
mPresContext->CompatibilityMode() != eCompatibility_FullStandards &&
|
2014-03-12 00:23:50 +04:00
|
|
|
!logicalBSize) {
|
2000-02-15 07:26:44 +03:00
|
|
|
// Check if it's a BR frame that is not alone on its line (it
|
2014-03-12 00:23:50 +04:00
|
|
|
// is given a block size of zero to indicate this), and if so reset
|
|
|
|
// blockStart and blockEnd so that BR frames don't influence the line.
|
2006-12-26 20:47:52 +03:00
|
|
|
if (nsGkAtoms::brFrame == frame->GetType()) {
|
2014-03-12 00:23:50 +04:00
|
|
|
blockStart = BLOCKDIR_ALIGN_FRAMES_NO_MINIMUM;
|
|
|
|
blockEnd = BLOCKDIR_ALIGN_FRAMES_NO_MAXIMUM;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (blockStart < minBCoord) minBCoord = blockStart;
|
|
|
|
if (blockEnd > maxBCoord) maxBCoord = blockEnd;
|
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" [frame]raw: a=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minBCoord=%d maxBCoord=%d\n",
|
|
|
|
pfd->mAscent, pfd->mBounds.BSize(lineWM),
|
2014-11-13 11:58:02 +03:00
|
|
|
pfd->mBorderPadding.Top(lineWM),
|
|
|
|
pfd->mBorderPadding.Bottom(lineWM),
|
2014-03-12 00:23:50 +04:00
|
|
|
logicalBSize,
|
|
|
|
frameSpan ? frameSpan->mBStartLeading : 0,
|
|
|
|
pfd->mBounds.BStart(lineWM), minBCoord, maxBCoord);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
if (psd != mRootSpan) {
|
2015-07-16 12:07:57 +03:00
|
|
|
frame->SetRect(lineWM, pfd->mBounds, ContainerSizeForSpan(psd));
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Factor in the minimum line block-size when handling the root-span for
|
1999-09-10 01:04:37 +04:00
|
|
|
// the block.
|
|
|
|
if (psd == mRootSpan) {
|
2000-02-15 07:26:44 +03:00
|
|
|
// We should factor in the block element's minimum line-height (as
|
|
|
|
// defined in section 10.8.1 of the css2 spec) assuming that
|
2015-02-19 12:39:19 +03:00
|
|
|
// zeroEffectiveSpanBox is not set on the root span. This only happens
|
2000-02-15 07:26:44 +03:00
|
|
|
// in some cases in quirks mode:
|
|
|
|
// (1) if the root span contains non-whitespace text directly (this
|
2015-02-19 12:39:19 +03:00
|
|
|
// is handled by zeroEffectiveSpanBox
|
2009-08-11 06:48:42 +04:00
|
|
|
// (2) if this line has a bullet
|
2000-02-15 07:26:44 +03:00
|
|
|
// (3) if this is the last line of an LI, DT, or DD element
|
|
|
|
// (The last line before a block also counts, but not before a
|
|
|
|
// BR) (NN4/IE5 quirk)
|
2009-08-11 06:48:42 +04:00
|
|
|
|
|
|
|
// (1) and (2) above
|
2015-02-19 12:39:19 +03:00
|
|
|
bool applyMinLH = !zeroEffectiveSpanBox || mHasBullet;
|
2014-12-09 09:47:26 +03:00
|
|
|
bool isLastLine = !mGotLineBox ||
|
|
|
|
(!mLineBox->IsLineWrapped() && !mLineEndsInBR);
|
2009-08-11 06:48:42 +04:00
|
|
|
if (!applyMinLH && isLastLine) {
|
2003-06-30 14:46:59 +04:00
|
|
|
nsIContent* blockContent = mRootSpan->mFrame->mFrame->GetContent();
|
|
|
|
if (blockContent) {
|
2003-11-19 04:20:56 +03:00
|
|
|
// (3) above, if the last line of LI, DT, or DD
|
2015-03-03 14:09:00 +03:00
|
|
|
if (blockContent->IsAnyOfHTMLElements(nsGkAtoms::li,
|
|
|
|
nsGkAtoms::dt,
|
|
|
|
nsGkAtoms::dd)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
applyMinLH = true;
|
2003-11-19 04:20:56 +03:00
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
2000-02-15 07:26:44 +03:00
|
|
|
if (applyMinLH) {
|
2012-09-28 05:56:40 +04:00
|
|
|
if (psd->mHasNonemptyContent || preMode || mHasBullet) {
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" [span]==> adjusting min/maxBCoord: currentValues: %d,%d", minBCoord, maxBCoord);
|
1999-09-10 01:04:37 +04:00
|
|
|
#endif
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord minimumLineBSize = mMinLineBSize;
|
|
|
|
nscoord blockStart =
|
2014-11-13 11:58:06 +03:00
|
|
|
-nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize,
|
|
|
|
lineWM.IsLineInverted());
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord blockEnd = blockStart + minimumLineBSize;
|
2009-05-19 02:13:12 +04:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
if (blockStart < minBCoord) minBCoord = blockStart;
|
|
|
|
if (blockEnd > maxBCoord) maxBCoord = blockEnd;
|
2000-02-02 10:38:23 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" new values: %d,%d\n", minBCoord, maxBCoord);
|
2009-04-22 03:53:52 +04:00
|
|
|
#endif
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" Used mMinLineBSize: %d, blockStart: %d, blockEnd: %d\n", mMinLineBSize, blockStart, blockEnd);
|
1999-09-10 01:04:37 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// XXX issues:
|
|
|
|
// [1] BR's on empty lines stop working
|
|
|
|
// [2] May not honor css2's notion of handling empty elements
|
|
|
|
// [3] blank lines in a pre-section ("\n") (handled with preMode)
|
2000-02-19 06:42:30 +03:00
|
|
|
|
|
|
|
// XXX Are there other problems with this?
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" [span]==> zapping min/maxBCoord: currentValues: %d,%d newValues: 0,0\n",
|
|
|
|
minBCoord, maxBCoord);
|
1999-09-10 01:04:37 +04:00
|
|
|
#endif
|
2014-03-12 00:23:50 +04:00
|
|
|
minBCoord = maxBCoord = 0;
|
1999-09-10 01:04:37 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
if ((minBCoord == BLOCKDIR_ALIGN_FRAMES_NO_MINIMUM) ||
|
|
|
|
(maxBCoord == BLOCKDIR_ALIGN_FRAMES_NO_MAXIMUM)) {
|
|
|
|
minBCoord = maxBCoord = baselineBCoord;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
|
|
|
|
2015-02-19 12:39:19 +03:00
|
|
|
if (psd != mRootSpan && zeroEffectiveSpanBox) {
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" [span]adjusting for zeroEffectiveSpanBox\n");
|
2014-03-12 00:23:50 +04:00
|
|
|
printf(" Original: minBCoord=%d, maxBCoord=%d, bSize=%d, ascent=%d, logicalBSize=%d, topLeading=%d, bottomLeading=%d\n",
|
|
|
|
minBCoord, maxBCoord, spanFramePFD->mBounds.BSize(frameWM),
|
2007-01-23 07:06:56 +03:00
|
|
|
spanFramePFD->mAscent,
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mLogicalBSize, psd->mBStartLeading, psd->mBEndLeading);
|
2000-02-19 06:42:30 +03:00
|
|
|
#endif
|
2014-11-13 11:58:02 +03:00
|
|
|
nscoord goodMinBCoord =
|
|
|
|
spanFramePFD->mBorderPadding.BStart(lineWM) - psd->mBStartLeading;
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord goodMaxBCoord = goodMinBCoord + psd->mLogicalBSize;
|
2012-01-02 02:35:12 +04:00
|
|
|
|
|
|
|
// For cases like the one in bug 714519 (text-decoration placement
|
2014-03-12 00:23:50 +04:00
|
|
|
// or making nsLineLayout::IsZeroBSize() handle
|
2012-01-02 02:35:12 +04:00
|
|
|
// vertical-align:top/bottom on a descendant of the line that's not
|
|
|
|
// a child of it), we want to treat elements that are
|
|
|
|
// vertical-align: top or bottom somewhat like children for the
|
|
|
|
// purposes of this quirk. To some extent, this is guessing, since
|
|
|
|
// they might end up being aligned anywhere. However, we'll guess
|
|
|
|
// that they'll be placed aligned with the top or bottom of this
|
|
|
|
// frame (as though this frame is the only thing in the line).
|
|
|
|
// (Guessing isn't crazy, since all we're doing is reducing the
|
|
|
|
// scope of a quirk and making the behavior more standards-like.)
|
2014-03-12 00:23:50 +04:00
|
|
|
if (maxStartBoxBSize > maxBCoord - minBCoord) {
|
|
|
|
// Distribute maxStartBoxBSize to ascent (baselineBCoord - minBCoord), and
|
|
|
|
// then to descent (maxBCoord - baselineBCoord) by adjusting minBCoord or
|
|
|
|
// maxBCoord, but not to exceed goodMinBCoord and goodMaxBCoord.
|
|
|
|
nscoord distribute = maxStartBoxBSize - (maxBCoord - minBCoord);
|
|
|
|
nscoord ascentSpace = std::max(minBCoord - goodMinBCoord, 0);
|
2012-01-02 02:35:12 +04:00
|
|
|
if (distribute > ascentSpace) {
|
|
|
|
distribute -= ascentSpace;
|
2014-03-12 00:23:50 +04:00
|
|
|
minBCoord -= ascentSpace;
|
|
|
|
nscoord descentSpace = std::max(goodMaxBCoord - maxBCoord, 0);
|
2012-01-02 02:35:12 +04:00
|
|
|
if (distribute > descentSpace) {
|
2014-03-12 00:23:50 +04:00
|
|
|
maxBCoord += descentSpace;
|
2012-01-02 02:35:12 +04:00
|
|
|
} else {
|
2014-03-12 00:23:50 +04:00
|
|
|
maxBCoord += distribute;
|
2012-01-02 02:35:12 +04:00
|
|
|
}
|
|
|
|
} else {
|
2014-03-12 00:23:50 +04:00
|
|
|
minBCoord -= distribute;
|
2012-01-02 02:35:12 +04:00
|
|
|
}
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (maxEndBoxBSize > maxBCoord - minBCoord) {
|
2012-01-02 02:35:12 +04:00
|
|
|
// Likewise, but preferring descent to ascent.
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord distribute = maxEndBoxBSize - (maxBCoord - minBCoord);
|
|
|
|
nscoord descentSpace = std::max(goodMaxBCoord - maxBCoord, 0);
|
2012-01-02 02:35:12 +04:00
|
|
|
if (distribute > descentSpace) {
|
|
|
|
distribute -= descentSpace;
|
2014-03-12 00:23:50 +04:00
|
|
|
maxBCoord += descentSpace;
|
|
|
|
nscoord ascentSpace = std::max(minBCoord - goodMinBCoord, 0);
|
2012-01-02 02:35:12 +04:00
|
|
|
if (distribute > ascentSpace) {
|
2014-03-12 00:23:50 +04:00
|
|
|
minBCoord -= ascentSpace;
|
2012-01-02 02:35:12 +04:00
|
|
|
} else {
|
2014-03-12 00:23:50 +04:00
|
|
|
minBCoord -= distribute;
|
2012-01-02 02:35:12 +04:00
|
|
|
}
|
|
|
|
} else {
|
2014-03-12 00:23:50 +04:00
|
|
|
maxBCoord += distribute;
|
2012-01-02 02:35:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
if (minBCoord > goodMinBCoord) {
|
|
|
|
nscoord adjust = minBCoord - goodMinBCoord; // positive
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
// shrink the logical extents
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mLogicalBSize -= adjust;
|
|
|
|
psd->mBStartLeading -= adjust;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (maxBCoord < goodMaxBCoord) {
|
|
|
|
nscoord adjust = goodMaxBCoord - maxBCoord;
|
|
|
|
psd->mLogicalBSize -= adjust;
|
|
|
|
psd->mBEndLeading -= adjust;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (minBCoord > 0) {
|
2000-02-15 07:26:44 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// shrink the content by moving its block start down. This is tricky,
|
|
|
|
// since the block start is the 0 for many coordinates, so what we do is
|
2000-02-15 07:26:44 +03:00
|
|
|
// move everything else up.
|
2014-03-12 00:23:50 +04:00
|
|
|
spanFramePFD->mAscent -= minBCoord; // move the baseline up
|
|
|
|
spanFramePFD->mBounds.BSize(lineWM) -= minBCoord; // move the block end up
|
|
|
|
psd->mBStartLeading += minBCoord;
|
|
|
|
*psd->mBaseline -= minBCoord;
|
2000-02-15 07:26:44 +03:00
|
|
|
|
|
|
|
pfd = psd->mFirstFrame;
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.BStart(lineWM) -= minBCoord; // move all the children
|
|
|
|
// back up
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerSizeForSpan(psd));
|
2000-02-15 07:26:44 +03:00
|
|
|
pfd = pfd->mNext;
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
maxBCoord -= minBCoord; // since minBCoord is in the frame's own
|
|
|
|
// coordinate system
|
|
|
|
minBCoord = 0;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (maxBCoord < spanFramePFD->mBounds.BSize(lineWM)) {
|
|
|
|
nscoord adjust = spanFramePFD->mBounds.BSize(lineWM) - maxBCoord;
|
|
|
|
spanFramePFD->mBounds.BSize(lineWM) -= adjust; // move the bottom up
|
|
|
|
psd->mBEndLeading += adjust;
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" New: minBCoord=%d, maxBCoord=%d, bSize=%d, ascent=%d, logicalBSize=%d, topLeading=%d, bottomLeading=%d\n",
|
|
|
|
minBCoord, maxBCoord, spanFramePFD->mBounds.BSize(lineWM),
|
2007-01-23 07:06:56 +03:00
|
|
|
spanFramePFD->mAscent,
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mLogicalBSize, psd->mBStartLeading, psd->mBEndLeading);
|
2000-02-19 06:42:30 +03:00
|
|
|
#endif
|
2000-02-15 07:26:44 +03:00
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mMinBCoord = minBCoord;
|
|
|
|
psd->mMaxBCoord = maxBCoord;
|
|
|
|
#ifdef NOISY_BLOCKDIR_ALIGN
|
|
|
|
printf(" [span]==> minBCoord=%d maxBCoord=%d delta=%d maxStartBoxBSize=%d maxEndBoxBSize=%d\n",
|
|
|
|
minBCoord, maxBCoord, maxBCoord - minBCoord, maxStartBoxBSize, maxEndBoxBSize);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
2014-03-12 00:23:50 +04:00
|
|
|
if (maxStartBoxBSize > mMaxStartBoxBSize) {
|
|
|
|
mMaxStartBoxBSize = maxStartBoxBSize;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
if (maxEndBoxBSize > mMaxEndBoxBSize) {
|
|
|
|
mMaxEndBoxBSize = maxEndBoxBSize;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-03 14:28:58 +04:00
|
|
|
static void SlideSpanFrameRect(nsIFrame* aFrame, nscoord aDeltaWidth)
|
|
|
|
{
|
2013-09-17 15:44:16 +04:00
|
|
|
// This should not use nsIFrame::MovePositionBy because it happens
|
|
|
|
// prior to relative positioning. In particular, because
|
|
|
|
// nsBlockFrame::PlaceLine calls aLineLayout.TrimTrailingWhiteSpace()
|
|
|
|
// prior to calling aLineLayout.RelativePositionFrames().
|
|
|
|
nsPoint p = aFrame->GetPosition();
|
|
|
|
p.x -= aDeltaWidth;
|
|
|
|
aFrame->SetPosition(p);
|
2006-05-03 14:28:58 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
1999-09-21 04:14:22 +04:00
|
|
|
nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord* aDeltaISize)
|
1999-09-21 04:14:22 +04:00
|
|
|
{
|
|
|
|
PerFrameData* pfd = psd->mFirstFrame;
|
|
|
|
if (!pfd) {
|
2014-03-12 00:23:50 +04:00
|
|
|
*aDeltaISize = 0;
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
pfd = pfd->Last();
|
2012-07-30 18:20:58 +04:00
|
|
|
while (nullptr != pfd) {
|
1999-09-24 21:23:33 +04:00
|
|
|
#ifdef REALLY_NOISY_TRIM
|
2014-12-10 01:40:14 +03:00
|
|
|
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": attempting trim of ");
|
1999-09-24 21:23:33 +04:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-09-24 21:23:33 +04:00
|
|
|
#endif
|
|
|
|
PerSpanData* childSpan = pfd->mSpan;
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
1999-09-24 21:23:33 +04:00
|
|
|
if (childSpan) {
|
1999-09-21 04:14:22 +04:00
|
|
|
// Maybe the child span has the trailing white-space in it?
|
2014-03-12 00:23:50 +04:00
|
|
|
if (TrimTrailingWhiteSpaceIn(childSpan, aDeltaISize)) {
|
|
|
|
nscoord deltaISize = *aDeltaISize;
|
|
|
|
if (deltaISize) {
|
1999-09-24 21:23:33 +04:00
|
|
|
// Adjust the child spans frame size
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.ISize(lineWM) -= deltaISize;
|
1999-09-21 04:14:22 +04:00
|
|
|
if (psd != mRootSpan) {
|
1999-09-24 21:23:33 +04:00
|
|
|
// When the child span is not a direct child of the block
|
|
|
|
// we need to update the child spans frame rectangle
|
|
|
|
// because it most likely will not be done again. Spans
|
|
|
|
// that are direct children of the block will be updated
|
2014-06-17 18:41:33 +04:00
|
|
|
// later, however, because the VerticalAlignFrames method
|
1999-09-24 21:23:33 +04:00
|
|
|
// will be run after this method.
|
2015-07-16 12:07:57 +03:00
|
|
|
nsSize containerSize = ContainerSizeForSpan(childSpan);
|
1999-09-24 21:23:33 +04:00
|
|
|
nsIFrame* f = pfd->mFrame;
|
2015-07-16 12:07:57 +03:00
|
|
|
LogicalRect r(lineWM, f->GetRect(), containerSize);
|
2014-03-12 00:23:50 +04:00
|
|
|
r.ISize(lineWM) -= deltaISize;
|
2015-07-16 12:07:57 +03:00
|
|
|
f->SetRect(lineWM, r, containerSize);
|
1999-09-24 21:23:33 +04:00
|
|
|
}
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
// Adjust the inline end edge of the span that contains the child span
|
|
|
|
psd->mICoord -= deltaISize;
|
1999-09-24 21:23:33 +04:00
|
|
|
|
|
|
|
// Slide any frames that follow the child span over by the
|
2014-03-12 00:23:50 +04:00
|
|
|
// correct amount. The only thing that can follow the child
|
1999-09-24 21:23:33 +04:00
|
|
|
// span is empty stuff, so we are just making things
|
|
|
|
// sensible (keeping the combined area honest).
|
|
|
|
while (pfd->mNext) {
|
|
|
|
pfd = pfd->mNext;
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.IStart(lineWM) -= deltaISize;
|
2006-05-03 14:28:58 +04:00
|
|
|
if (psd != mRootSpan) {
|
|
|
|
// When the child span is not a direct child of the block
|
2014-03-12 00:23:50 +04:00
|
|
|
// we need to update the child span's frame rectangle
|
2006-05-03 14:28:58 +04:00
|
|
|
// because it most likely will not be done again. Spans
|
|
|
|
// that are direct children of the block will be updated
|
2014-06-17 18:41:33 +04:00
|
|
|
// later, however, because the VerticalAlignFrames method
|
2006-05-03 14:28:58 +04:00
|
|
|
// will be run after this method.
|
2014-03-12 00:23:50 +04:00
|
|
|
SlideSpanFrameRect(pfd->mFrame, deltaISize);
|
2006-05-03 14:28:58 +04:00
|
|
|
}
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
}
|
2014-12-23 02:22:26 +03:00
|
|
|
else if (!pfd->mIsTextFrame && !pfd->mSkipWhenTrimmingWhitespace) {
|
2004-03-02 04:23:13 +03:00
|
|
|
// If we hit a frame on the end that's not text and not a placeholder,
|
|
|
|
// then there is no trailing whitespace to trim. Stop the search.
|
2014-03-12 00:23:50 +04:00
|
|
|
*aDeltaISize = 0;
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
2014-12-23 02:22:26 +03:00
|
|
|
else if (pfd->mIsTextFrame) {
|
2007-12-01 12:24:24 +03:00
|
|
|
// Call TrimTrailingWhiteSpace even on empty textframes because they
|
|
|
|
// might have a soft hyphen which should now appear, changing the frame's
|
|
|
|
// width
|
|
|
|
nsTextFrame::TrimOutput trimOutput = static_cast<nsTextFrame*>(pfd->mFrame)->
|
|
|
|
TrimTrailingWhiteSpace(mBlockReflowState->rendContext);
|
1999-09-24 21:23:33 +04:00
|
|
|
#ifdef NOISY_TRIM
|
2014-12-10 01:40:14 +03:00
|
|
|
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": trim of ");
|
1999-10-30 06:52:11 +04:00
|
|
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
2007-12-01 12:24:24 +03:00
|
|
|
printf(" returned %d\n", trimOutput.mDeltaWidth);
|
1999-09-24 21:23:33 +04:00
|
|
|
#endif
|
2014-11-10 04:25:17 +03:00
|
|
|
|
2007-12-01 12:24:24 +03:00
|
|
|
if (trimOutput.mChanged) {
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mRecomputeOverflow = true;
|
2007-12-01 12:24:24 +03:00
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
// Delta width not being zero means that
|
|
|
|
// there is trimmed space in the frame.
|
2007-12-01 12:24:24 +03:00
|
|
|
if (trimOutput.mDeltaWidth) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.ISize(lineWM) -= trimOutput.mDeltaWidth;
|
1999-09-21 04:14:22 +04:00
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
// If any trailing space is trimmed, the justification opportunity
|
|
|
|
// generated by the space should be removed as well.
|
|
|
|
pfd->mJustificationInfo.CancelOpportunityForTrimmedSpace();
|
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
// See if the text frame has already been placed in its parent
|
|
|
|
if (psd != mRootSpan) {
|
|
|
|
// The frame was already placed during psd's
|
|
|
|
// reflow. Update the frames rectangle now.
|
2014-10-22 16:14:41 +04:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds,
|
2015-07-16 12:07:57 +03:00
|
|
|
ContainerSizeForSpan(psd));
|
1999-10-30 06:52:11 +04:00
|
|
|
}
|
1999-09-21 04:14:22 +04:00
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
// Adjust containing span's right edge
|
2014-03-12 00:23:50 +04:00
|
|
|
psd->mICoord -= trimOutput.mDeltaWidth;
|
1999-09-21 04:14:22 +04:00
|
|
|
|
1999-10-30 06:52:11 +04:00
|
|
|
// Slide any frames that follow the text frame over by the
|
|
|
|
// right amount. The only thing that can follow the text
|
|
|
|
// frame is empty stuff, so we are just making things
|
|
|
|
// sensible (keeping the combined area honest).
|
|
|
|
while (pfd->mNext) {
|
|
|
|
pfd = pfd->mNext;
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.IStart(lineWM) -= trimOutput.mDeltaWidth;
|
2006-05-03 14:28:58 +04:00
|
|
|
if (psd != mRootSpan) {
|
|
|
|
// When the child span is not a direct child of the block
|
|
|
|
// we need to update the child spans frame rectangle
|
|
|
|
// because it most likely will not be done again. Spans
|
|
|
|
// that are direct children of the block will be updated
|
2014-06-17 18:41:33 +04:00
|
|
|
// later, however, because the VerticalAlignFrames method
|
2006-05-03 14:28:58 +04:00
|
|
|
// will be run after this method.
|
2007-12-01 12:24:24 +03:00
|
|
|
SlideSpanFrameRect(pfd->mFrame, trimOutput.mDeltaWidth);
|
2006-05-03 14:28:58 +04:00
|
|
|
}
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-23 02:22:26 +03:00
|
|
|
if (pfd->mIsNonEmptyTextFrame || trimOutput.mChanged) {
|
2007-12-01 12:24:24 +03:00
|
|
|
// Pass up to caller so they can shrink their span
|
2014-03-12 00:23:50 +04:00
|
|
|
*aDeltaISize = trimOutput.mDeltaWidth;
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-12-01 12:24:24 +03:00
|
|
|
}
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
pfd = pfd->mPrev;
|
|
|
|
}
|
1999-10-30 06:52:11 +04:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
*aDeltaISize = 0;
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
1999-09-21 04:14:22 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
1999-09-21 04:14:22 +04:00
|
|
|
nsLineLayout::TrimTrailingWhiteSpace()
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
1999-09-21 04:14:22 +04:00
|
|
|
PerSpanData* psd = mRootSpan;
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord deltaISize;
|
|
|
|
TrimTrailingWhiteSpaceIn(psd, &deltaISize);
|
|
|
|
return 0 != deltaISize;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2015-01-07 04:47:09 +03:00
|
|
|
bool
|
|
|
|
nsLineLayout::PerFrameData::ParticipatesInJustification() const
|
|
|
|
{
|
|
|
|
if (mIsBullet || mIsEmpty || mSkipWhenTrimmingWhitespace) {
|
|
|
|
// Skip bullets, empty frames, and placeholders
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (mIsTextFrame && !mIsNonWhitespaceTextFrame &&
|
|
|
|
static_cast<nsTextFrame*>(mFrame)->IsAtEndOfLine()) {
|
|
|
|
// Skip trimmed whitespaces
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
struct nsLineLayout::JustificationComputationState
|
2014-11-02 17:07:00 +03:00
|
|
|
{
|
2014-12-15 02:19:38 +03:00
|
|
|
PerFrameData* mFirstParticipant;
|
2014-11-10 04:25:17 +03:00
|
|
|
PerFrameData* mLastParticipant;
|
2015-02-17 08:01:49 +03:00
|
|
|
// When we are going across a boundary of ruby base, i.e. entering
|
|
|
|
// one, leaving one, or both, the following fields will be set to
|
|
|
|
// the corresponding ruby base frame for handling ruby-align.
|
|
|
|
PerFrameData* mLastExitedRubyBase;
|
|
|
|
PerFrameData* mLastEnteredRubyBase;
|
2014-12-15 02:19:38 +03:00
|
|
|
|
|
|
|
JustificationComputationState()
|
|
|
|
: mFirstParticipant(nullptr)
|
|
|
|
, mLastParticipant(nullptr)
|
2015-02-17 08:01:49 +03:00
|
|
|
, mLastExitedRubyBase(nullptr)
|
|
|
|
, mLastEnteredRubyBase(nullptr) { }
|
2014-11-10 04:25:17 +03:00
|
|
|
};
|
2000-04-17 18:40:46 +04:00
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
static bool
|
|
|
|
IsRubyAlignSpaceAround(nsIFrame* aRubyBase)
|
|
|
|
{
|
|
|
|
return aRubyBase->StyleText()->mRubyAlign == NS_STYLE_RUBY_ALIGN_SPACE_AROUND;
|
|
|
|
}
|
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
/**
|
|
|
|
* Assign justification gaps for justification
|
|
|
|
* opportunities across two frames.
|
|
|
|
*/
|
|
|
|
/* static */ int
|
|
|
|
nsLineLayout::AssignInterframeJustificationGaps(
|
|
|
|
PerFrameData* aFrame, JustificationComputationState& aState)
|
|
|
|
{
|
|
|
|
PerFrameData* prev = aState.mLastParticipant;
|
|
|
|
MOZ_ASSERT(prev);
|
|
|
|
|
|
|
|
auto& assign = aFrame->mJustificationAssignment;
|
|
|
|
auto& prevAssign = prev->mJustificationAssignment;
|
2015-02-17 08:01:49 +03:00
|
|
|
|
|
|
|
if (aState.mLastExitedRubyBase || aState.mLastEnteredRubyBase) {
|
|
|
|
PerFrameData* exitedRubyBase = aState.mLastExitedRubyBase;
|
|
|
|
if (!exitedRubyBase || IsRubyAlignSpaceAround(exitedRubyBase->mFrame)) {
|
|
|
|
prevAssign.mGapsAtEnd = 1;
|
|
|
|
} else {
|
|
|
|
exitedRubyBase->mJustificationAssignment.mGapsAtEnd = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PerFrameData* enteredRubyBase = aState.mLastEnteredRubyBase;
|
|
|
|
if (!enteredRubyBase || IsRubyAlignSpaceAround(enteredRubyBase->mFrame)) {
|
|
|
|
assign.mGapsAtStart = 1;
|
|
|
|
} else {
|
|
|
|
enteredRubyBase->mJustificationAssignment.mGapsAtStart = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are no longer going across a ruby base boundary.
|
|
|
|
aState.mLastExitedRubyBase = nullptr;
|
|
|
|
aState.mLastEnteredRubyBase = nullptr;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
const auto& info = aFrame->mJustificationInfo;
|
|
|
|
const auto& prevInfo = prev->mJustificationInfo;
|
2015-02-17 08:01:49 +03:00
|
|
|
if (!info.mIsStartJustifiable && !prevInfo.mIsEndJustifiable) {
|
2015-02-17 08:01:49 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
if (!info.mIsStartJustifiable) {
|
2015-02-17 08:01:49 +03:00
|
|
|
prevAssign.mGapsAtEnd = 2;
|
|
|
|
assign.mGapsAtStart = 0;
|
|
|
|
} else if (!prevInfo.mIsEndJustifiable) {
|
|
|
|
prevAssign.mGapsAtEnd = 0;
|
|
|
|
assign.mGapsAtStart = 2;
|
|
|
|
} else {
|
|
|
|
prevAssign.mGapsAtEnd = 1;
|
|
|
|
assign.mGapsAtStart = 1;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
/**
|
2014-12-15 01:57:36 +03:00
|
|
|
* Compute the justification info of the given span, and store the
|
|
|
|
* number of inner opportunities into the frame's justification info.
|
|
|
|
* It returns the number of non-inner opportunities it detects.
|
2014-11-10 04:25:17 +03:00
|
|
|
*/
|
|
|
|
int32_t
|
|
|
|
nsLineLayout::ComputeFrameJustification(PerSpanData* aPSD,
|
|
|
|
JustificationComputationState& aState)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aPSD, "null arg");
|
|
|
|
NS_ASSERTION(!aState.mLastParticipant || !aState.mLastParticipant->mSpan,
|
|
|
|
"Last participant shall always be a leaf frame");
|
2014-12-15 01:57:36 +03:00
|
|
|
bool firstChild = true;
|
|
|
|
int32_t& innerOpportunities =
|
|
|
|
aPSD->mFrame->mJustificationInfo.mInnerOpportunities;
|
|
|
|
MOZ_ASSERT(innerOpportunities == 0,
|
|
|
|
"Justification info should not have been set yet.");
|
|
|
|
int32_t outerOpportunities = 0;
|
2000-04-17 18:40:46 +04:00
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd; pfd = pfd->mNext) {
|
|
|
|
if (!pfd->ParticipatesInJustification()) {
|
|
|
|
continue;
|
2014-11-04 12:59:46 +03:00
|
|
|
}
|
2014-11-02 17:07:00 +03:00
|
|
|
|
2014-12-15 02:19:38 +03:00
|
|
|
bool isRubyBase = pfd->mFrame->GetType() == nsGkAtoms::rubyBaseFrame;
|
2015-02-17 08:01:49 +03:00
|
|
|
PerFrameData* outerRubyBase = aState.mLastEnteredRubyBase;
|
2014-12-15 02:19:38 +03:00
|
|
|
if (isRubyBase) {
|
2015-02-17 08:01:49 +03:00
|
|
|
aState.mLastEnteredRubyBase = pfd;
|
2014-12-15 02:19:38 +03:00
|
|
|
}
|
|
|
|
|
2014-12-15 01:57:36 +03:00
|
|
|
int extraOpportunities = 0;
|
2014-11-10 04:25:17 +03:00
|
|
|
if (pfd->mSpan) {
|
|
|
|
PerSpanData* span = pfd->mSpan;
|
2014-12-15 01:57:36 +03:00
|
|
|
extraOpportunities = ComputeFrameJustification(span, aState);
|
|
|
|
innerOpportunities += pfd->mJustificationInfo.mInnerOpportunities;
|
2014-11-10 04:25:17 +03:00
|
|
|
} else {
|
2014-12-23 02:22:26 +03:00
|
|
|
if (pfd->mIsTextFrame) {
|
2015-02-17 08:01:49 +03:00
|
|
|
innerOpportunities += pfd->mJustificationInfo.mInnerOpportunities;
|
2014-11-10 04:25:17 +03:00
|
|
|
}
|
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
if (!aState.mLastParticipant) {
|
2014-12-15 02:19:38 +03:00
|
|
|
aState.mFirstParticipant = pfd;
|
2015-02-17 08:01:49 +03:00
|
|
|
// It is not an empty ruby base, but we are not assigning gaps
|
|
|
|
// to the content for now. Clear the last entered ruby base so
|
|
|
|
// that we can correctly set the last exited ruby base.
|
|
|
|
aState.mLastEnteredRubyBase = nullptr;
|
2014-12-15 02:19:38 +03:00
|
|
|
} else {
|
2015-02-17 08:01:49 +03:00
|
|
|
extraOpportunities = AssignInterframeJustificationGaps(pfd, aState);
|
2014-11-10 04:25:17 +03:00
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
|
2014-11-10 04:25:17 +03:00
|
|
|
aState.mLastParticipant = pfd;
|
2015-01-07 04:47:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isRubyBase) {
|
2015-02-17 08:01:49 +03:00
|
|
|
if (aState.mLastEnteredRubyBase == pfd) {
|
|
|
|
// There is no justification participant inside this ruby base.
|
|
|
|
// Ignore this ruby base completely and restore the outer ruby
|
|
|
|
// base here.
|
|
|
|
aState.mLastEnteredRubyBase = outerRubyBase;
|
|
|
|
} else {
|
|
|
|
aState.mLastExitedRubyBase = pfd;
|
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
2014-12-15 01:57:36 +03:00
|
|
|
|
|
|
|
if (firstChild) {
|
|
|
|
outerOpportunities = extraOpportunities;
|
|
|
|
firstChild = false;
|
|
|
|
} else {
|
|
|
|
innerOpportunities += extraOpportunities;
|
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
|
2014-12-15 01:57:36 +03:00
|
|
|
return outerOpportunities;
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
|
2014-12-09 09:43:24 +03:00
|
|
|
void
|
|
|
|
nsLineLayout::AdvanceAnnotationInlineBounds(PerFrameData* aPFD,
|
2015-07-16 12:07:57 +03:00
|
|
|
const nsSize& aContainerSize,
|
2014-12-09 09:43:24 +03:00
|
|
|
nscoord aDeltaICoord,
|
|
|
|
nscoord aDeltaISize)
|
|
|
|
{
|
2014-12-13 08:13:12 +03:00
|
|
|
nsIFrame* frame = aPFD->mFrame;
|
|
|
|
nsIAtom* frameType = frame->GetType();
|
|
|
|
MOZ_ASSERT(frameType == nsGkAtoms::rubyTextFrame ||
|
|
|
|
frameType == nsGkAtoms::rubyTextContainerFrame);
|
2014-12-09 09:43:24 +03:00
|
|
|
MOZ_ASSERT(aPFD->mSpan, "rt and rtc should have span.");
|
|
|
|
|
2014-12-13 08:13:12 +03:00
|
|
|
PerSpanData* psd = aPFD->mSpan;
|
2014-12-09 09:43:24 +03:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2015-01-07 04:47:09 +03:00
|
|
|
aPFD->mBounds.IStart(lineWM) += aDeltaICoord;
|
2014-12-13 08:13:12 +03:00
|
|
|
|
|
|
|
// Check whether this expansion should be counted into the reserved
|
|
|
|
// isize or not. When it is a ruby text container, and it has some
|
|
|
|
// children linked to the base, it must not have reserved isize,
|
|
|
|
// or its children won't align with their bases. Otherwise, this
|
|
|
|
// expansion should be reserved. There are two cases a ruby text
|
|
|
|
// container does not have children linked to the base:
|
|
|
|
// 1. it is a container for span; 2. its children are collapsed.
|
|
|
|
// See bug 1055674 for the second case.
|
|
|
|
if (frameType == nsGkAtoms::rubyTextFrame ||
|
|
|
|
// This ruby text container is a span.
|
|
|
|
(psd->mFirstFrame == psd->mLastFrame && psd->mFirstFrame &&
|
|
|
|
!psd->mFirstFrame->mIsLinkedToBase)) {
|
2015-03-11 02:28:21 +03:00
|
|
|
// For ruby text frames, only increase frames
|
|
|
|
// which are not auto-hidden.
|
|
|
|
if (frameType != nsGkAtoms::rubyTextFrame ||
|
|
|
|
!static_cast<nsRubyTextFrame*>(frame)->IsAutoHidden()) {
|
|
|
|
nscoord reservedISize = RubyUtils::GetReservedISize(frame);
|
|
|
|
RubyUtils::SetReservedISize(frame, reservedISize + aDeltaISize);
|
|
|
|
}
|
2014-12-13 08:13:12 +03:00
|
|
|
} else {
|
|
|
|
// It is a normal ruby text container. Its children will expand
|
|
|
|
// themselves properly. We only need to expand its own size here.
|
2015-01-07 04:47:09 +03:00
|
|
|
aPFD->mBounds.ISize(lineWM) += aDeltaISize;
|
2014-12-13 08:13:12 +03:00
|
|
|
}
|
2015-07-16 12:07:57 +03:00
|
|
|
aPFD->mFrame->SetRect(lineWM, aPFD->mBounds, aContainerSize);
|
2014-12-09 09:43:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function applies the changes of icoord and isize caused by
|
|
|
|
* justification to annotations of the given frame.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsLineLayout::ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
|
|
|
|
nscoord aDeltaICoord,
|
|
|
|
nscoord aDeltaISize)
|
|
|
|
{
|
|
|
|
PerFrameData* pfd = aPFD->mNextAnnotation;
|
|
|
|
while (pfd) {
|
2015-07-16 12:07:57 +03:00
|
|
|
nsSize containerSize = pfd->mFrame->GetParent()->GetSize();
|
|
|
|
AdvanceAnnotationInlineBounds(pfd, containerSize,
|
2014-12-09 09:43:24 +03:00
|
|
|
aDeltaICoord, aDeltaISize);
|
|
|
|
|
|
|
|
// There are two cases where an annotation frame has siblings which
|
|
|
|
// do not attached to a ruby base-level frame:
|
|
|
|
// 1. there's an intra-annotation whitespace which has no intra-base
|
|
|
|
// white-space to pair with;
|
|
|
|
// 2. there are not enough ruby bases to be paired with annotations.
|
|
|
|
// In these cases, their size should not be affected, but we still
|
|
|
|
// need to move them so that they won't overlap other frames.
|
|
|
|
PerFrameData* sibling = pfd->mNext;
|
2014-12-23 02:22:26 +03:00
|
|
|
while (sibling && !sibling->mIsLinkedToBase) {
|
2015-07-16 12:07:57 +03:00
|
|
|
AdvanceAnnotationInlineBounds(sibling, containerSize,
|
2014-12-09 09:43:24 +03:00
|
|
|
aDeltaICoord + aDeltaISize, 0);
|
|
|
|
sibling = sibling->mNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
pfd = pfd->mNextAnnotation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
nscoord
|
2014-11-10 04:25:17 +03:00
|
|
|
nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
|
|
|
|
JustificationApplicationState& aState)
|
2000-04-17 18:40:46 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aPSD, "null arg");
|
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
nscoord deltaICoord = 0;
|
2012-07-30 18:20:58 +04:00
|
|
|
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nullptr; pfd = pfd->mNext) {
|
2000-04-17 18:40:46 +04:00
|
|
|
// Don't reposition bullets (and other frames that occur out of X-order?)
|
2014-12-23 02:22:26 +03:00
|
|
|
if (!pfd->mIsBullet) {
|
2000-04-17 18:40:46 +04:00
|
|
|
nscoord dw = 0;
|
2014-03-24 21:50:13 +04:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2014-12-15 02:19:38 +03:00
|
|
|
const auto& assign = pfd->mJustificationAssignment;
|
2014-03-12 00:23:50 +04:00
|
|
|
|
2014-12-23 02:22:26 +03:00
|
|
|
if (true == pfd->mIsTextFrame) {
|
2014-11-10 04:25:17 +03:00
|
|
|
if (aState.IsJustifiable()) {
|
|
|
|
// Set corresponding justification gaps here, so that the
|
|
|
|
// text frame knows how it should add gaps at its sides.
|
|
|
|
const auto& info = pfd->mJustificationInfo;
|
|
|
|
auto textFrame = static_cast<nsTextFrame*>(pfd->mFrame);
|
|
|
|
textFrame->AssignJustificationGaps(assign);
|
|
|
|
dw = aState.Consume(JustificationUtils::CountGaps(info, assign));
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
|
2007-09-24 06:19:14 +04:00
|
|
|
if (dw) {
|
2014-12-23 02:22:26 +03:00
|
|
|
pfd->mRecomputeOverflow = true;
|
2007-09-24 06:19:14 +04:00
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
else {
|
2012-07-30 18:20:58 +04:00
|
|
|
if (nullptr != pfd->mSpan) {
|
2014-11-10 04:25:17 +03:00
|
|
|
dw = ApplyFrameJustification(pfd->mSpan, aState);
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
}
|
2004-03-16 09:58:01 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.ISize(lineWM) += dw;
|
2015-02-17 08:01:49 +03:00
|
|
|
nscoord gapsAtEnd = 0;
|
2014-12-15 02:19:38 +03:00
|
|
|
if (!pfd->mIsTextFrame && assign.TotalGaps()) {
|
|
|
|
// It is possible that we assign gaps to non-text frame.
|
|
|
|
// Apply the gaps as margin around the frame.
|
|
|
|
deltaICoord += aState.Consume(assign.mGapsAtStart);
|
2015-02-17 08:01:49 +03:00
|
|
|
gapsAtEnd = aState.Consume(assign.mGapsAtEnd);
|
|
|
|
dw += gapsAtEnd;
|
2014-12-15 02:19:38 +03:00
|
|
|
}
|
|
|
|
pfd->mBounds.IStart(lineWM) += deltaICoord;
|
2014-03-12 00:23:50 +04:00
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
// The gaps added to the end of the frame should also be
|
|
|
|
// excluded from the isize added to the annotation.
|
2015-02-24 06:46:29 +03:00
|
|
|
ApplyLineJustificationToAnnotations(pfd, deltaICoord, dw - gapsAtEnd);
|
2014-03-12 00:23:50 +04:00
|
|
|
deltaICoord += dw;
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerSizeForSpan(aPSD));
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
return deltaICoord;
|
2000-04-17 18:40:46 +04:00
|
|
|
}
|
|
|
|
|
2015-02-17 08:01:49 +03:00
|
|
|
static nsIFrame*
|
|
|
|
FindNearestRubyBaseAncestor(nsIFrame* aFrame)
|
|
|
|
{
|
2015-03-11 02:28:21 +03:00
|
|
|
MOZ_ASSERT(aFrame->StyleContext()->ShouldSuppressLineBreak());
|
2015-02-17 08:01:49 +03:00
|
|
|
while (aFrame && aFrame->GetType() != nsGkAtoms::rubyBaseFrame) {
|
|
|
|
aFrame = aFrame->GetParent();
|
|
|
|
}
|
2015-03-04 05:04:11 +03:00
|
|
|
// XXX It is possible that no ruby base ancestor is found because of
|
|
|
|
// some edge cases like form control or canvas inside ruby text.
|
|
|
|
// See bug 1138092 comment 4.
|
2015-04-20 06:04:09 +03:00
|
|
|
NS_WARN_IF_FALSE(aFrame, "no ruby base ancestor?");
|
2015-02-17 08:01:49 +03:00
|
|
|
return aFrame;
|
|
|
|
}
|
|
|
|
|
2014-12-15 02:33:59 +03:00
|
|
|
/**
|
|
|
|
* This method expands the given frame by the given reserved isize.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsLineLayout::ExpandRubyBox(PerFrameData* aFrame, nscoord aReservedISize,
|
2015-07-16 12:07:57 +03:00
|
|
|
const nsSize& aContainerSize)
|
2014-12-15 02:33:59 +03:00
|
|
|
{
|
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
2015-02-17 08:01:49 +03:00
|
|
|
auto rubyAlign = aFrame->mFrame->StyleText()->mRubyAlign;
|
|
|
|
switch (rubyAlign) {
|
|
|
|
case NS_STYLE_RUBY_ALIGN_START:
|
|
|
|
// do nothing for start
|
|
|
|
break;
|
|
|
|
case NS_STYLE_RUBY_ALIGN_SPACE_BETWEEN:
|
|
|
|
case NS_STYLE_RUBY_ALIGN_SPACE_AROUND: {
|
|
|
|
int32_t opportunities = aFrame->mJustificationInfo.mInnerOpportunities;
|
|
|
|
int32_t gaps = opportunities * 2;
|
|
|
|
if (rubyAlign == NS_STYLE_RUBY_ALIGN_SPACE_AROUND) {
|
|
|
|
// Each expandable ruby box with ruby-align space-around has a
|
|
|
|
// gap at each of its sides. For rb/rbc, see comment in
|
|
|
|
// AssignInterframeJustificationGaps; for rt/rtc, see comment
|
|
|
|
// in ExpandRubyBoxWithAnnotations.
|
|
|
|
gaps += 2;
|
|
|
|
}
|
|
|
|
if (gaps > 0) {
|
|
|
|
JustificationApplicationState state(gaps, aReservedISize);
|
|
|
|
ApplyFrameJustification(aFrame->mSpan, state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// If there are no justification opportunities for space-between,
|
|
|
|
// fall-through to center per spec.
|
|
|
|
}
|
|
|
|
case NS_STYLE_RUBY_ALIGN_CENTER:
|
|
|
|
// Indent all children by half of the reserved inline size.
|
|
|
|
for (PerFrameData* child = aFrame->mSpan->mFirstFrame;
|
|
|
|
child; child = child->mNext) {
|
|
|
|
child->mBounds.IStart(lineWM) += aReservedISize / 2;
|
2015-07-16 12:07:57 +03:00
|
|
|
child->mFrame->SetRect(lineWM, child->mBounds, aContainerSize);
|
2015-02-17 08:01:49 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Unknown ruby-align value");
|
|
|
|
}
|
|
|
|
|
2014-12-15 02:33:59 +03:00
|
|
|
aFrame->mBounds.ISize(lineWM) += aReservedISize;
|
2015-07-16 12:07:57 +03:00
|
|
|
aFrame->mFrame->SetRect(lineWM, aFrame->mBounds, aContainerSize);
|
2014-12-15 02:33:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method expands the given frame by the reserved inline size.
|
|
|
|
* It also expands its annotations if they are expandable and have
|
|
|
|
* reserved isize larger than zero.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsLineLayout::ExpandRubyBoxWithAnnotations(PerFrameData* aFrame,
|
2015-07-16 12:07:57 +03:00
|
|
|
const nsSize& aContainerSize)
|
2014-12-15 02:33:59 +03:00
|
|
|
{
|
|
|
|
nscoord reservedISize = RubyUtils::GetReservedISize(aFrame->mFrame);
|
|
|
|
if (reservedISize) {
|
2015-07-16 12:07:57 +03:00
|
|
|
ExpandRubyBox(aFrame, reservedISize, aContainerSize);
|
2014-12-15 02:33:59 +03:00
|
|
|
}
|
|
|
|
|
2015-03-14 08:46:33 +03:00
|
|
|
WritingMode lineWM = mRootSpan->mWritingMode;
|
|
|
|
bool isLevelContainer =
|
|
|
|
aFrame->mFrame->GetType() == nsGkAtoms::rubyBaseContainerFrame;
|
2014-12-15 02:33:59 +03:00
|
|
|
for (PerFrameData* annotation = aFrame->mNextAnnotation;
|
|
|
|
annotation; annotation = annotation->mNextAnnotation) {
|
2015-03-14 08:46:33 +03:00
|
|
|
if (isLevelContainer) {
|
|
|
|
nsIFrame* rtcFrame = annotation->mFrame;
|
|
|
|
MOZ_ASSERT(rtcFrame->GetType() == nsGkAtoms::rubyTextContainerFrame);
|
|
|
|
// It is necessary to set the rect again because the container
|
|
|
|
// width was unknown, and zero was used instead when we reflow
|
|
|
|
// them. The corresponding base containers were repositioned in
|
|
|
|
// VerticalAlignFrames and PlaceTopBottomFrames.
|
|
|
|
MOZ_ASSERT(
|
|
|
|
rtcFrame->GetLogicalSize(lineWM) == annotation->mBounds.Size(lineWM));
|
|
|
|
rtcFrame->SetPosition(lineWM, annotation->mBounds.Origin(lineWM),
|
2015-07-16 12:07:57 +03:00
|
|
|
aContainerSize);
|
2015-03-14 08:46:33 +03:00
|
|
|
}
|
|
|
|
|
2014-12-15 02:33:59 +03:00
|
|
|
nscoord reservedISize = RubyUtils::GetReservedISize(annotation->mFrame);
|
|
|
|
if (!reservedISize) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(annotation->mSpan);
|
|
|
|
JustificationComputationState computeState;
|
|
|
|
ComputeFrameJustification(annotation->mSpan, computeState);
|
|
|
|
if (!computeState.mFirstParticipant) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-02-20 03:45:49 +03:00
|
|
|
if (IsRubyAlignSpaceAround(annotation->mFrame)) {
|
2015-02-17 08:01:49 +03:00
|
|
|
// Add one gap at each side of this annotation.
|
|
|
|
computeState.mFirstParticipant->mJustificationAssignment.mGapsAtStart = 1;
|
|
|
|
computeState.mLastParticipant->mJustificationAssignment.mGapsAtEnd = 1;
|
|
|
|
}
|
2015-01-13 12:04:41 +03:00
|
|
|
nsIFrame* parentFrame = annotation->mFrame->GetParent();
|
2015-07-16 12:07:57 +03:00
|
|
|
nsSize containerSize = parentFrame->GetSize();
|
|
|
|
MOZ_ASSERT(containerSize == aContainerSize ||
|
2015-01-13 12:04:41 +03:00
|
|
|
parentFrame->GetType() == nsGkAtoms::rubyTextContainerFrame,
|
|
|
|
"Container width should only be different when the current "
|
|
|
|
"annotation is a ruby text frame, whose parent is not same "
|
|
|
|
"as its base frame.");
|
2015-07-16 12:07:57 +03:00
|
|
|
ExpandRubyBox(annotation, reservedISize, containerSize);
|
2014-12-15 02:33:59 +03:00
|
|
|
ExpandInlineRubyBoxes(annotation->mSpan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method looks for all expandable ruby box in the given span, and
|
|
|
|
* calls ExpandRubyBox to expand them in depth-first preorder.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsLineLayout::ExpandInlineRubyBoxes(PerSpanData* aSpan)
|
|
|
|
{
|
2015-07-16 12:07:57 +03:00
|
|
|
nsSize containerSize = ContainerSizeForSpan(aSpan);
|
2014-12-15 02:33:59 +03:00
|
|
|
for (PerFrameData* pfd = aSpan->mFirstFrame; pfd; pfd = pfd->mNext) {
|
|
|
|
if (RubyUtils::IsExpandableRubyBox(pfd->mFrame)) {
|
2015-07-16 12:07:57 +03:00
|
|
|
ExpandRubyBoxWithAnnotations(pfd, containerSize);
|
2014-12-15 02:33:59 +03:00
|
|
|
}
|
|
|
|
if (pfd->mSpan) {
|
|
|
|
ExpandInlineRubyBoxes(pfd->mSpan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-17 18:41:33 +04:00
|
|
|
// Align inline frames within the line according to the CSS text-align
|
|
|
|
// property.
|
Bug 300030: Move intrinsic width computation out of nsIFrame::Reflow and into its own methods on nsIFrame. Replace reflow reasons, types, and commands with dirty bits/notifications. Thanks to bzbarsky for almost all of the HTML form controls (mozilla/layout/forms) changes, and many others for help testing and patching. For detailed commit logs, see REFLOW_YYYYMMDD_BRANCH, where YYYYMMDD is one of 20061031, 20060830, 20060603, 20060302, 20060119, 20051011, 20050804, 20050429, 20050315, 20050111, and 20041213.
2006-12-08 08:38:33 +03:00
|
|
|
void
|
2014-06-17 18:41:33 +04:00
|
|
|
nsLineLayout::TextAlignLine(nsLineBox* aLine,
|
|
|
|
bool aIsLastLine)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2012-01-12 21:52:21 +04:00
|
|
|
/**
|
|
|
|
* NOTE: aIsLastLine ain't necessarily so: it is correctly set by caller
|
|
|
|
* only in cases where the last line needs special handling.
|
|
|
|
*/
|
1999-03-19 00:03:25 +03:00
|
|
|
PerSpanData* psd = mRootSpan;
|
2014-04-16 12:03:28 +04:00
|
|
|
WritingMode lineWM = psd->mWritingMode;
|
2015-06-16 02:36:11 +03:00
|
|
|
LAYOUT_WARN_IF_FALSE(psd->mIEnd != NS_UNCONSTRAINEDSIZE,
|
2015-06-16 02:36:12 +03:00
|
|
|
"have unconstrained width; this should only result from "
|
|
|
|
"very large sizes, not attempts at intrinsic width "
|
|
|
|
"calculation");
|
2014-04-16 12:03:28 +04:00
|
|
|
nscoord availISize = psd->mIEnd - psd->mIStart;
|
|
|
|
nscoord remainingISize = availISize - aLine->ISize();
|
2014-03-12 00:23:50 +04:00
|
|
|
#ifdef NOISY_INLINEDIR_ALIGN
|
2013-10-28 00:56:32 +04:00
|
|
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
2014-04-16 12:03:28 +04:00
|
|
|
printf(": availISize=%d lineBounds.IStart=%d lineISize=%d delta=%d\n",
|
|
|
|
availISize, aLine->IStart(), aLine->ISize(), remainingISize);
|
1999-03-19 00:03:25 +03:00
|
|
|
#endif
|
2012-01-12 21:52:21 +04:00
|
|
|
|
2013-10-28 00:56:32 +04:00
|
|
|
// 'text-align-last: auto' is equivalent to the value of the 'text-align'
|
|
|
|
// property except when 'text-align' is set to 'justify', in which case it
|
|
|
|
// is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise.
|
|
|
|
//
|
|
|
|
// XXX: the code below will have to change when we implement text-justify
|
|
|
|
//
|
|
|
|
nscoord dx = 0;
|
|
|
|
uint8_t textAlign = mStyleText->mTextAlign;
|
|
|
|
bool textAlignTrue = mStyleText->mTextAlignTrue;
|
|
|
|
if (aIsLastLine) {
|
|
|
|
textAlignTrue = mStyleText->mTextAlignLastTrue;
|
|
|
|
if (mStyleText->mTextAlignLast == NS_STYLE_TEXT_ALIGN_AUTO) {
|
|
|
|
if (textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
|
|
|
|
textAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
|
2012-01-12 21:52:21 +04:00
|
|
|
}
|
2013-10-28 00:56:32 +04:00
|
|
|
} else {
|
|
|
|
textAlign = mStyleText->mTextAlignLast;
|
2012-01-12 21:52:21 +04:00
|
|
|
}
|
2013-10-28 00:56:32 +04:00
|
|
|
}
|
|
|
|
|
2014-12-13 14:18:16 +03:00
|
|
|
bool isSVG = mBlockReflowState->frame->IsSVGText();
|
|
|
|
bool doTextAlign = remainingISize > 0 || textAlignTrue;
|
2012-01-12 21:52:21 +04:00
|
|
|
|
2014-12-15 02:19:38 +03:00
|
|
|
int32_t additionalGaps = 0;
|
2014-12-13 14:18:16 +03:00
|
|
|
if (!isSVG && (mHasRuby || (doTextAlign &&
|
|
|
|
textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY))) {
|
2014-12-15 02:19:38 +03:00
|
|
|
JustificationComputationState computeState;
|
2014-12-15 01:57:36 +03:00
|
|
|
ComputeFrameJustification(psd, computeState);
|
2014-12-15 02:19:38 +03:00
|
|
|
if (mHasRuby && computeState.mFirstParticipant) {
|
|
|
|
PerFrameData* firstFrame = computeState.mFirstParticipant;
|
2015-03-11 02:28:21 +03:00
|
|
|
if (firstFrame->mFrame->StyleContext()->ShouldSuppressLineBreak()) {
|
2014-12-15 02:19:38 +03:00
|
|
|
MOZ_ASSERT(!firstFrame->mJustificationAssignment.mGapsAtStart);
|
2015-02-17 08:01:49 +03:00
|
|
|
nsIFrame* rubyBase = FindNearestRubyBaseAncestor(firstFrame->mFrame);
|
2015-03-04 05:04:11 +03:00
|
|
|
if (rubyBase && IsRubyAlignSpaceAround(rubyBase)) {
|
2015-02-17 08:01:49 +03:00
|
|
|
firstFrame->mJustificationAssignment.mGapsAtStart = 1;
|
|
|
|
additionalGaps++;
|
|
|
|
}
|
2014-12-15 02:19:38 +03:00
|
|
|
}
|
|
|
|
PerFrameData* lastFrame = computeState.mLastParticipant;
|
2015-03-11 02:28:21 +03:00
|
|
|
if (lastFrame->mFrame->StyleContext()->ShouldSuppressLineBreak()) {
|
2014-12-15 02:19:38 +03:00
|
|
|
MOZ_ASSERT(!lastFrame->mJustificationAssignment.mGapsAtEnd);
|
2015-02-17 08:01:49 +03:00
|
|
|
nsIFrame* rubyBase = FindNearestRubyBaseAncestor(lastFrame->mFrame);
|
2015-03-04 05:04:11 +03:00
|
|
|
if (rubyBase && IsRubyAlignSpaceAround(rubyBase)) {
|
2015-02-17 08:01:49 +03:00
|
|
|
lastFrame->mJustificationAssignment.mGapsAtEnd = 1;
|
|
|
|
additionalGaps++;
|
|
|
|
}
|
2014-12-15 02:19:38 +03:00
|
|
|
}
|
|
|
|
}
|
2014-12-13 14:18:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isSVG && doTextAlign) {
|
2012-01-12 21:52:21 +04:00
|
|
|
switch (textAlign) {
|
2014-11-10 04:25:17 +03:00
|
|
|
case NS_STYLE_TEXT_ALIGN_JUSTIFY: {
|
2014-12-15 01:57:36 +03:00
|
|
|
int32_t opportunities =
|
|
|
|
psd->mFrame->mJustificationInfo.mInnerOpportunities;
|
2014-11-10 04:25:17 +03:00
|
|
|
if (opportunities > 0) {
|
2014-12-15 02:19:38 +03:00
|
|
|
int32_t gaps = opportunities * 2 + additionalGaps;
|
|
|
|
JustificationApplicationState applyState(gaps, remainingISize);
|
2000-04-17 18:40:46 +04:00
|
|
|
|
2012-01-12 21:52:21 +04:00
|
|
|
// Apply the justification, and make sure to update our linebox
|
|
|
|
// width to account for it.
|
2014-11-10 04:25:17 +03:00
|
|
|
aLine->ExpandBy(ApplyFrameJustification(psd, applyState),
|
2015-07-16 12:07:57 +03:00
|
|
|
ContainerSizeForSpan(psd));
|
2014-11-10 04:25:17 +03:00
|
|
|
|
|
|
|
MOZ_ASSERT(applyState.mGaps.mHandled == applyState.mGaps.mCount,
|
|
|
|
"Unprocessed justification gaps");
|
|
|
|
MOZ_ASSERT(applyState.mWidth.mConsumed == applyState.mWidth.mAvailable,
|
|
|
|
"Unprocessed justification width");
|
2012-01-12 21:52:21 +04:00
|
|
|
break;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2012-01-12 21:52:21 +04:00
|
|
|
// Fall through to the default case if we could not justify to fill
|
|
|
|
// the space.
|
2014-11-10 04:25:17 +03:00
|
|
|
}
|
2006-12-12 21:28:37 +03:00
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_DEFAULT:
|
2014-03-12 00:23:50 +04:00
|
|
|
// default alignment is to start edge so do nothing
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_LEFT:
|
|
|
|
case NS_STYLE_TEXT_ALIGN_MOZ_LEFT:
|
|
|
|
if (!lineWM.IsBidiLTR()) {
|
2014-04-16 12:03:28 +04:00
|
|
|
dx = remainingISize;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
break;
|
2006-12-12 21:28:37 +03:00
|
|
|
|
|
|
|
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
|
|
|
case NS_STYLE_TEXT_ALIGN_MOZ_RIGHT:
|
2014-03-12 00:23:50 +04:00
|
|
|
if (lineWM.IsBidiLTR()) {
|
2014-04-16 12:03:28 +04:00
|
|
|
dx = remainingISize;
|
2014-03-11 12:22:52 +04:00
|
|
|
}
|
2014-03-12 00:23:50 +04:00
|
|
|
break;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2014-03-12 00:23:50 +04:00
|
|
|
case NS_STYLE_TEXT_ALIGN_END:
|
2014-04-16 12:03:28 +04:00
|
|
|
dx = remainingISize;
|
2014-03-11 12:22:52 +04:00
|
|
|
break;
|
2014-03-11 09:19:03 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
case NS_STYLE_TEXT_ALIGN_CENTER:
|
1999-03-25 06:49:29 +03:00
|
|
|
case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
|
2014-04-16 12:03:28 +04:00
|
|
|
dx = remainingISize / 2;
|
1999-03-19 00:03:25 +03:00
|
|
|
break;
|
|
|
|
}
|
2004-06-20 13:51:10 +04:00
|
|
|
}
|
2009-05-12 12:18:27 +04:00
|
|
|
|
2014-12-15 02:33:59 +03:00
|
|
|
if (mHasRuby) {
|
|
|
|
ExpandInlineRubyBoxes(mRootSpan);
|
|
|
|
}
|
|
|
|
|
2014-09-30 21:59:13 +04:00
|
|
|
if (mPresContext->BidiEnabled() &&
|
|
|
|
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
|
|
|
|
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
|
|
|
|
aLine->GetChildCount(),
|
2015-04-08 02:22:34 +03:00
|
|
|
lineWM, mContainerSize,
|
2014-09-30 21:59:13 +04:00
|
|
|
psd->mIStart + mTextIndent + dx);
|
|
|
|
if (dx) {
|
2015-07-16 12:07:57 +03:00
|
|
|
aLine->IndentBy(dx, ContainerSize());
|
2014-09-30 21:59:13 +04:00
|
|
|
}
|
|
|
|
} else if (dx) {
|
2009-05-12 12:18:27 +04:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2014-03-12 00:23:50 +04:00
|
|
|
pfd->mBounds.IStart(lineWM) += dx;
|
2015-07-16 12:07:57 +03:00
|
|
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerSizeForSpan(psd));
|
1999-05-08 04:48:39 +04:00
|
|
|
}
|
2015-07-16 12:07:57 +03:00
|
|
|
aLine->IndentBy(dx, ContainerSize());
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-13 12:04:41 +03:00
|
|
|
// This method applies any relative positioning to the given frame.
|
|
|
|
void
|
|
|
|
nsLineLayout::ApplyRelativePositioning(PerFrameData* aPFD)
|
|
|
|
{
|
|
|
|
if (!aPFD->mRelativePos) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* frame = aPFD->mFrame;
|
|
|
|
WritingMode frameWM = frame->GetWritingMode();
|
2015-07-16 12:07:57 +03:00
|
|
|
LogicalPoint origin = frame->GetLogicalPosition(ContainerSize());
|
2015-01-13 12:04:41 +03:00
|
|
|
// right and bottom are handled by
|
|
|
|
// nsHTMLReflowState::ComputeRelativeOffsets
|
|
|
|
nsHTMLReflowState::ApplyRelativePositioning(frame, frameWM,
|
|
|
|
aPFD->mOffsets, &origin,
|
2015-07-16 12:07:57 +03:00
|
|
|
ContainerSize());
|
|
|
|
frame->SetPosition(frameWM, origin, ContainerSize());
|
2015-01-13 12:04:41 +03:00
|
|
|
}
|
|
|
|
|
2015-01-13 12:04:41 +03:00
|
|
|
// This method do relative positioning for ruby annotations.
|
|
|
|
void
|
|
|
|
nsLineLayout::RelativePositionAnnotations(PerSpanData* aRubyPSD,
|
|
|
|
nsOverflowAreas& aOverflowAreas)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aRubyPSD->mFrame->mFrame->GetType() == nsGkAtoms::rubyFrame);
|
|
|
|
for (PerFrameData* pfd = aRubyPSD->mFirstFrame; pfd; pfd = pfd->mNext) {
|
|
|
|
MOZ_ASSERT(pfd->mFrame->GetType() == nsGkAtoms::rubyBaseContainerFrame);
|
|
|
|
for (PerFrameData* rtc = pfd->mNextAnnotation;
|
|
|
|
rtc; rtc = rtc->mNextAnnotation) {
|
|
|
|
nsIFrame* rtcFrame = rtc->mFrame;
|
|
|
|
MOZ_ASSERT(rtcFrame->GetType() == nsGkAtoms::rubyTextContainerFrame);
|
|
|
|
ApplyRelativePositioning(rtc);
|
|
|
|
nsOverflowAreas rtcOverflowAreas;
|
|
|
|
RelativePositionFrames(rtc->mSpan, rtcOverflowAreas);
|
|
|
|
aOverflowAreas.UnionWith(rtcOverflowAreas + rtcFrame->GetPosition());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
void
|
2010-10-07 08:25:45 +04:00
|
|
|
nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflowAreas)
|
1999-03-19 00:03:25 +03:00
|
|
|
{
|
2010-10-07 08:25:45 +04:00
|
|
|
nsOverflowAreas overflowAreas;
|
2014-03-12 00:23:50 +04:00
|
|
|
WritingMode wm = psd->mWritingMode;
|
2014-12-10 01:40:14 +03:00
|
|
|
if (psd != mRootSpan) {
|
2010-10-07 08:25:45 +04:00
|
|
|
// The span's overflow areas come in three parts:
|
2004-08-25 17:03:28 +04:00
|
|
|
// -- this frame's width and height
|
2010-10-07 08:25:45 +04:00
|
|
|
// -- pfd->mOverflowAreas, which is the area of a bullet or the union
|
2004-08-25 17:03:28 +04:00
|
|
|
// of a relatively positioned frame's absolute children
|
|
|
|
// -- the bounds of all inline descendants
|
|
|
|
// The former two parts are computed right here, we gather the descendants
|
|
|
|
// below.
|
2007-12-12 04:43:09 +03:00
|
|
|
// At this point psd->mFrame->mBounds might be out of date since
|
|
|
|
// bidi reordering can move and resize the frames. So use the frame's
|
|
|
|
// rect instead of mBounds.
|
|
|
|
nsRect adjustedBounds(nsPoint(0, 0), psd->mFrame->mFrame->GetSize());
|
2008-06-13 02:02:32 +04:00
|
|
|
|
2010-10-07 08:25:45 +04:00
|
|
|
overflowAreas.ScrollableOverflow().UnionRect(
|
|
|
|
psd->mFrame->mOverflowAreas.ScrollableOverflow(), adjustedBounds);
|
|
|
|
overflowAreas.VisualOverflow().UnionRect(
|
|
|
|
psd->mFrame->mOverflowAreas.VisualOverflow(), adjustedBounds);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-03-12 00:23:50 +04:00
|
|
|
LogicalRect rect(wm, psd->mIStart, mBStartEdge,
|
|
|
|
psd->mICoord - psd->mIStart, mFinalLineBSize);
|
1999-03-19 00:03:25 +03:00
|
|
|
// The minimum combined area for the frames that are direct
|
|
|
|
// children of the block starts at the upper left corner of the
|
1999-10-13 03:27:32 +04:00
|
|
|
// line and is sized to match the size of the line's bounding box
|
2014-06-17 18:41:33 +04:00
|
|
|
// (the same size as the values returned from VerticalAlignFrames)
|
2015-07-16 12:07:57 +03:00
|
|
|
overflowAreas.VisualOverflow() = rect.GetPhysicalRect(wm, ContainerSize());
|
2010-10-07 08:25:45 +04:00
|
|
|
overflowAreas.ScrollableOverflow() = overflowAreas.VisualOverflow();
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2004-02-28 05:55:58 +03:00
|
|
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
2003-08-01 02:03:26 +04:00
|
|
|
nsIFrame* frame = pfd->mFrame;
|
1999-03-19 00:03:25 +03:00
|
|
|
|
|
|
|
// Adjust the origin of the frame
|
2015-01-13 12:04:41 +03:00
|
|
|
ApplyRelativePositioning(pfd);
|
1999-03-19 00:03:25 +03:00
|
|
|
|
2003-08-07 03:59:10 +04:00
|
|
|
// We must position the view correctly before positioning its
|
|
|
|
// descendants so that widgets are positioned properly (since only
|
|
|
|
// some views have widgets).
|
|
|
|
if (frame->HasView())
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
|
2010-10-07 08:25:45 +04:00
|
|
|
frame->GetView(), pfd->mOverflowAreas.VisualOverflow(),
|
|
|
|
NS_FRAME_NO_SIZE_VIEW);
|
2003-08-07 03:59:10 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Note: the combined area of a child is in its coordinate
|
|
|
|
// system. We adjust the childs combined area into our coordinate
|
|
|
|
// system before computing the aggregated value by adding in
|
|
|
|
// <b>x</b> and <b>y</b> which were computed above.
|
2010-10-07 08:25:45 +04:00
|
|
|
nsOverflowAreas r;
|
1999-03-19 00:03:25 +03:00
|
|
|
if (pfd->mSpan) {
|
|
|
|
// Compute a new combined area for the child span before
|
|
|
|
// aggregating it into our combined area.
|
2004-08-25 17:03:28 +04:00
|
|
|
RelativePositionFrames(pfd->mSpan, r);
|
2003-08-07 03:59:10 +04:00
|
|
|
} else {
|
2010-10-07 08:25:45 +04:00
|
|
|
r = pfd->mOverflowAreas;
|
2014-12-23 02:22:26 +03:00
|
|
|
if (pfd->mIsTextFrame) {
|
2011-08-03 22:30:58 +04:00
|
|
|
// We need to recompute overflow areas in two cases:
|
|
|
|
// (1) When PFD_RECOMPUTEOVERFLOW is set due to trimming
|
|
|
|
// (2) When there are text decorations, since we can't recompute the
|
2014-06-17 18:41:33 +04:00
|
|
|
// overflow area until Reflow and VerticalAlignLine have finished
|
2014-12-23 02:22:26 +03:00
|
|
|
if (pfd->mRecomputeOverflow ||
|
2013-02-16 09:38:33 +04:00
|
|
|
frame->StyleContext()->HasTextDecorationLines()) {
|
2007-11-09 09:49:38 +03:00
|
|
|
nsTextFrame* f = static_cast<nsTextFrame*>(frame);
|
2015-03-07 23:27:36 +03:00
|
|
|
r = f->RecomputeOverflow(mBlockReflowState->frame);
|
2007-11-09 09:49:38 +03:00
|
|
|
}
|
2010-10-07 08:25:45 +04:00
|
|
|
frame->FinishAndStoreOverflow(r, frame->GetSize());
|
2007-09-24 06:19:14 +04:00
|
|
|
}
|
2004-08-25 17:03:28 +04:00
|
|
|
|
2003-08-07 03:59:10 +04:00
|
|
|
// If we have something that's not an inline but with a complex frame
|
|
|
|
// hierarchy inside that contains views, they need to be
|
|
|
|
// positioned.
|
|
|
|
// All descendant views must be repositioned even if this frame
|
|
|
|
// does have a view in case this frame's view does not have a
|
|
|
|
// widget and some of the descendant views do have widgets --
|
|
|
|
// otherwise the widgets won't be repositioned.
|
2004-12-27 18:05:18 +03:00
|
|
|
nsContainerFrame::PositionChildViews(frame);
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2009-04-06 04:31:50 +04:00
|
|
|
// Do this here (rather than along with setting the overflow rect
|
|
|
|
// below) so we get leaf frames as well. No need to worry
|
2003-08-01 02:03:26 +04:00
|
|
|
// about the root span, since it doesn't have a frame.
|
|
|
|
if (frame->HasView())
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
|
2010-10-07 08:25:45 +04:00
|
|
|
frame->GetView(),
|
|
|
|
r.VisualOverflow(),
|
2003-08-07 03:59:10 +04:00
|
|
|
NS_FRAME_NO_MOVE_VIEW);
|
2003-08-01 02:03:26 +04:00
|
|
|
|
2015-01-07 10:10:07 +03:00
|
|
|
overflowAreas.UnionWith(r + frame->GetPosition());
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
|
|
|
|
2015-01-13 12:04:41 +03:00
|
|
|
// Also compute relative position in the annotations.
|
|
|
|
if (psd->mFrame->mFrame->GetType() == nsGkAtoms::rubyFrame) {
|
|
|
|
RelativePositionAnnotations(psd, overflowAreas);
|
|
|
|
}
|
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// If we just computed a spans combined area, we need to update its
|
2009-04-06 04:31:50 +04:00
|
|
|
// overflow rect...
|
2014-12-10 01:40:14 +03:00
|
|
|
if (psd != mRootSpan) {
|
2004-02-28 05:55:58 +03:00
|
|
|
PerFrameData* spanPFD = psd->mFrame;
|
|
|
|
nsIFrame* frame = spanPFD->mFrame;
|
2010-10-07 08:25:45 +04:00
|
|
|
frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|
2010-10-07 08:25:45 +04:00
|
|
|
aOverflowAreas = overflowAreas;
|
1999-03-19 00:03:25 +03:00
|
|
|
}
|