GetIntrinsicWidth for mroot, mfenced, and mfrac. b=363240, r+sr=roc

This commit is contained in:
karlt+@karlt.net 2008-03-13 22:02:49 -07:00
Родитель e387e0eeb1
Коммит 15c6fd9ec5
6 изменённых файлов: 215 добавлений и 46 удалений

Просмотреть файл

@ -243,6 +243,13 @@ nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext,
mOpenChar, mCloseChar, mSeparatorsChar, mSeparatorsCount);
}
/* virtual */ nscoord
nsMathMLmfencedFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext)
{
return doGetIntrinsicWidth(aRenderingContext, this, mOpenChar, mCloseChar,
mSeparatorsChar, mSeparatorsCount);
}
// exported routine that both mfenced and mfrac share.
// mfrac uses this when its bevelled attribute is set.
/*static*/ nsresult
@ -468,6 +475,32 @@ nsMathMLmfencedFrame::doReflow(nsPresContext* aPresContext,
return NS_OK;
}
static void
GetCharSpacing(nsMathMLChar* aMathMLChar,
nsOperatorFlags aForm,
PRInt32 aScriptLevel,
nscoord em,
nscoord& aLeftSpace,
nscoord& aRightSpace)
{
nsAutoString data;
aMathMLChar->GetData(data);
nsOperatorFlags flags = 0;
float lspace = 0.0f;
float rspace = 0.0f;
PRBool found = nsMathMLOperators::LookupOperator(data, aForm,
&flags, &lspace, &rspace);
// We don't want extra space when we are a script
if (found && aScriptLevel > 0) {
lspace /= 2.0f;
rspace /= 2.0f;
}
aLeftSpace = NSToCoordRound(lspace * em);
aRightSpace = NSToCoordRound(rspace * em);
}
// helper functions to perform the common task of formatting our chars
/*static*/ nsresult
nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
@ -483,20 +516,9 @@ nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
nscoord& aDescent)
{
if (aMathMLChar && 0 < aMathMLChar->Length()) {
nsOperatorFlags flags = 0;
float leftSpace = 0.0f;
float rightSpace = 0.0f;
nsAutoString data;
aMathMLChar->GetData(data);
PRBool found = nsMathMLOperators::LookupOperator(data, aForm,
&flags, &leftSpace, &rightSpace);
// If we don't want extra space when we are a script
if (found && aScriptLevel > 0) {
leftSpace /= 2.0f;
rightSpace /= 2.0f;
}
nscoord leftSpace;
nscoord rightSpace;
GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
// stretch the char to the appropriate height if it is not big enough.
nsBoundingMetrics charSize;
@ -515,6 +537,8 @@ nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
// GetBoundingMetrics failed)
leading = 0;
if (NS_FAILED(res)) {
nsAutoString data;
aMathMLChar->GetData(data);
nsTextDimensions dimensions;
aRenderingContext.GetTextDimensions(data.get(), data.Length(), dimensions);
charSize.ascent = dimensions.ascent;
@ -532,11 +556,11 @@ nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
aDescent = charSize.descent + leading;
// account the spacing
charSize.width += NSToCoordRound((leftSpace + rightSpace) * em);
charSize.width += leftSpace + rightSpace;
// x-origin is used to store lspace ...
// y-origin is used to stored the ascent ...
aMathMLChar->SetRect(nsRect(NSToCoordRound(leftSpace * em),
aMathMLChar->SetRect(nsRect(leftSpace,
charSize.ascent, charSize.width,
charSize.ascent + charSize.descent));
}
@ -553,6 +577,7 @@ nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar,
// the char's x-origin was used to store lspace ...
// the char's y-origin was used to store the ascent ...
// the char's width was used to store the advance with (with spacing) ...
nsRect rect;
aMathMLChar->GetRect(rect);
@ -574,6 +599,77 @@ nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar,
dx += rect.width;
}
static nscoord
GetMaxCharWidth(nsPresContext* aPresContext,
nsIRenderingContext* aRenderingContext,
nsMathMLChar* aMathMLChar,
nsOperatorFlags aForm,
PRInt32 aScriptLevel,
nscoord em)
{
nscoord width = aMathMLChar->GetMaxWidth(aPresContext, *aRenderingContext);
if (0 < aMathMLChar->Length()) {
nscoord leftSpace;
nscoord rightSpace;
GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
width += leftSpace + rightSpace;
}
return width;
}
/* virtual */ nscoord
nsMathMLmfencedFrame::doGetIntrinsicWidth(nsIRenderingContext* aRenderingContext,
nsMathMLContainerFrame* aForFrame,
nsMathMLChar* aOpenChar,
nsMathMLChar* aCloseChar,
nsMathMLChar* aSeparatorsChar,
PRInt32 aSeparatorsCount)
{
nscoord width = 0;
nsPresContext* presContext = aForFrame->PresContext();
const nsStyleFont* font = aForFrame->GetStyleFont();
nsCOMPtr<nsIFontMetrics> fm = presContext->GetMetricsFor(font->mFont);
nscoord em;
GetEmHeight(fm, em);
if (aOpenChar) {
width +=
GetMaxCharWidth(presContext, aRenderingContext, aOpenChar,
NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em);
}
PRInt32 i = 0;
nsIFrame* childFrame = aForFrame->GetFirstChild(nsnull);
while (childFrame) {
// XXX This includes margin while Reflow currently doesn't consider
// margin, so we may end up with too much space, but, with stretchy
// characters, this is an approximation anyway.
width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
nsLayoutUtils::PREF_WIDTH);
if (i < aSeparatorsCount) {
width +=
GetMaxCharWidth(presContext, aRenderingContext, &aSeparatorsChar[i],
NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em);
}
i++;
childFrame = childFrame->GetNextSibling();
}
if (aCloseChar) {
width +=
GetMaxCharWidth(presContext, aRenderingContext, aCloseChar,
NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em);
}
return width;
}
nscoord
nsMathMLmfencedFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
{

Просмотреть файл

@ -74,6 +74,9 @@ public:
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
virtual nscoord
GetIntrinsicWidth(nsIRenderingContext* aRenderingContext);
NS_IMETHOD
AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
@ -87,8 +90,8 @@ public:
virtual nscoord
FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize);
// exported routine that both mfenced and mfrac share.
// mfrac uses this when its bevelled attribute is set.
// exported routines that both mfenced and mfrac share.
// mfrac uses these when its bevelled attribute is set.
static nsresult
doReflow(nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
@ -100,6 +103,14 @@ public:
nsMathMLChar* aSeparatorsChar,
PRInt32 aSeparatorsCount);
static nscoord
doGetIntrinsicWidth(nsIRenderingContext* aRenderingContext,
nsMathMLContainerFrame* aForFrame,
nsMathMLChar* aOpenChar,
nsMathMLChar* aCloseChar,
nsMathMLChar* aSeparatorsChar,
PRInt32 aSeparatorsCount);
// helper routines to format the MathMLChars involved here
static nsresult
ReflowChar(nsPresContext* aPresContext,

Просмотреть файл

@ -246,6 +246,20 @@ nsMathMLmfracFrame::Reflow(nsPresContext* aPresContext,
aReflowState, aStatus);
}
/* virtual */ nscoord
nsMathMLmfracFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext)
{
if (mSlashChar) {
// bevelled rendering
return nsMathMLmfencedFrame::doGetIntrinsicWidth(aRenderingContext, this,
nsnull, nsnull,
mSlashChar, 1);
}
// default rendering
return nsMathMLContainerFrame::GetIntrinsicWidth(aRenderingContext);
}
nscoord
nsMathMLmfracFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
{

Просмотреть файл

@ -112,6 +112,9 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
virtual nscoord
GetIntrinsicWidth(nsIRenderingContext* aRenderingContext);
NS_IMETHOD
Place(nsIRenderingContext& aRenderingContext,
PRBool aPlaceOrigin,

Просмотреть файл

@ -152,6 +152,44 @@ nsMathMLmrootFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return rv;
}
static void
GetRadicalXOffsets(nscoord aIndexWidth, nscoord aSqrWidth,
nsIFontMetrics* aFontMetrics,
nscoord* aIndexOffset, nscoord* aSqrOffset)
{
// The index is tucked in closer to the radical while making sure
// that the kern does not make the index and radical collide
nscoord dxIndex, dxSqr;
nscoord xHeight = 0;
aFontMetrics->GetXHeight(xHeight);
nscoord indexRadicalKern = NSToCoordRound(1.35f * xHeight);
if (indexRadicalKern > aIndexWidth) {
dxIndex = indexRadicalKern - aIndexWidth;
dxSqr = 0;
}
else {
dxIndex = 0;
dxSqr = aIndexWidth - indexRadicalKern;
}
// avoid collision by leaving a minimum space between index and radical
nscoord minimumClearance = aSqrWidth/2;
if (dxIndex + aIndexWidth + minimumClearance > dxSqr + aSqrWidth) {
if (aIndexWidth + minimumClearance < aSqrWidth) {
dxIndex = aSqrWidth - (aIndexWidth + minimumClearance);
dxSqr = 0;
}
else {
dxIndex = 0;
dxSqr = (aIndexWidth + minimumClearance) - aSqrWidth;
}
}
if (aIndexOffset)
*aIndexOffset = dxIndex;
if (aSqrOffset)
*aSqrOffset = dxSqr;
}
NS_IMETHODIMP
nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -314,36 +352,12 @@ nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext,
aDesiredSize.height = aDesiredSize.ascent + descent;
}
// the index is tucked in closer to the radical while making sure
// that the kern does not make the index and radical collide
nscoord dxIndex, dxSqr, dx, dy;
nscoord xHeight = 0;
fm->GetXHeight(xHeight);
nscoord indexRadicalKern = NSToCoordRound(1.35f * xHeight);
if (indexRadicalKern > bmIndex.width) {
dxIndex = indexRadicalKern - bmIndex.width;
dxSqr = 0;
}
else {
dxIndex = 0;
dxSqr = bmIndex.width - indexRadicalKern;
}
// avoid collision by leaving a minimun space between index and radical
nscoord minimumClearance = bmSqr.width/2;
if (dxIndex + bmIndex.width + minimumClearance > dxSqr + bmSqr.width) {
if (bmIndex.width + minimumClearance < bmSqr.width) {
dxIndex = bmSqr.width - (bmIndex.width + minimumClearance);
dxSqr = 0;
}
else {
dxIndex = 0;
dxSqr = (bmIndex.width + minimumClearance) - bmSqr.width;
}
}
nscoord dxIndex, dxSqr;
GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr);
// place the index
dx = dxIndex;
dy = aDesiredSize.ascent - (indexRaisedAscent + indexSize.ascent - bmIndex.ascent);
nscoord dx = dxIndex;
nscoord dy = aDesiredSize.ascent - (indexRaisedAscent + indexSize.ascent - bmIndex.ascent);
FinishReflowChild(indexFrame, aPresContext, nsnull, indexSize, dx, dy, 0);
// place the radical symbol and the radical bar
@ -375,6 +389,34 @@ nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext,
return NS_OK;
}
/* virtual */ nscoord
nsMathMLmrootFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext)
{
nsIFrame* baseFrame = mFrames.FirstChild();
nsIFrame* indexFrame = nsnull;
if (baseFrame)
indexFrame = baseFrame->GetNextSibling();
if (!indexFrame || indexFrame->GetNextSibling()) {
nsHTMLReflowMetrics desiredSize;
ReflowError(*aRenderingContext, desiredSize);
return desiredSize.width;
}
nscoord baseWidth =
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, baseFrame,
nsLayoutUtils::PREF_WIDTH);
nscoord indexWidth =
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, indexFrame,
nsLayoutUtils::PREF_WIDTH);
nscoord sqrWidth = mSqrChar.GetMaxWidth(PresContext(), *aRenderingContext);
nsCOMPtr<nsIFontMetrics> fm;
aRenderingContext->GetFontMetrics(*getter_AddRefs(fm));
nscoord dxSqr;
GetRadicalXOffsets(indexWidth, sqrWidth, fm, nsnull, &dxSqr);
return dxSqr + baseWidth;
}
// ----------------------
// the Style System will use these to pass the proper style context to our MathMLChar

Просмотреть файл

@ -72,6 +72,9 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
virtual nscoord
GetIntrinsicWidth(nsIRenderingContext* aRenderingContext);
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);