michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #include "nsMathMLmmultiscriptsFrame.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsRenderingContext.h" michael@0: #include michael@0: michael@0: using mozilla::WritingMode; michael@0: michael@0: // michael@0: // -- attach prescripts and tensor indices to a base - implementation michael@0: // -- attach a subscript to a base - implementation michael@0: // -- attach a subscript-superscript pair to a base - implementation michael@0: // -- attach a superscript to a base - implementation michael@0: // michael@0: michael@0: nsIFrame* michael@0: NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame) michael@0: michael@0: nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame() michael@0: { michael@0: } michael@0: michael@0: uint8_t michael@0: nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame* aFrame) michael@0: { michael@0: if (!aFrame) michael@0: return 0; michael@0: if (mFrames.ContainsFrame(aFrame)) { michael@0: if (mFrames.FirstChild() == aFrame || michael@0: aFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) { michael@0: return 0; // No script increment for base frames or prescript markers michael@0: } michael@0: return 1; michael@0: } michael@0: return 0; //not a child michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMathMLmmultiscriptsFrame::TransmitAutomaticData() michael@0: { michael@0: // if our base is an embellished operator, let its state bubble to us michael@0: mPresentationData.baseFrame = mFrames.FirstChild(); michael@0: GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData); michael@0: michael@0: // The TeXbook (Ch 17. p.141) says the superscript inherits the compression michael@0: // while the subscript is compressed. So here we collect subscripts and set michael@0: // the compression flag in them. michael@0: michael@0: int32_t count = 0; michael@0: bool isSubScript = mContent->Tag() != nsGkAtoms::msup_; michael@0: michael@0: nsAutoTArray subScriptFrames; michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: if (childFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) { michael@0: // mprescripts frame michael@0: } else if (0 == count) { michael@0: // base frame michael@0: } else { michael@0: // super/subscript block michael@0: if (isSubScript) { michael@0: // subscript michael@0: subScriptFrames.AppendElement(childFrame); michael@0: } else { michael@0: // superscript michael@0: } michael@0: PropagateFrameFlagFor(childFrame, NS_FRAME_MATHML_SCRIPT_DESCENDANT); michael@0: isSubScript = !isSubScript; michael@0: } michael@0: count++; michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: for (int32_t i = subScriptFrames.Length() - 1; i >= 0; i--) { michael@0: childFrame = subScriptFrames[i]; michael@0: PropagatePresentationDataFor(childFrame, michael@0: NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* virtual */ nsresult michael@0: nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext, michael@0: bool aPlaceOrigin, michael@0: nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: nscoord subScriptShift = 0; michael@0: nscoord supScriptShift = 0; michael@0: nsIAtom* tag = mContent->Tag(); michael@0: michael@0: // subscriptshift michael@0: // michael@0: // "Specifies the minimum amount to shift the baseline of subscript down; the michael@0: // default is for the rendering agent to use its own positioning rules." michael@0: // michael@0: // values: length michael@0: // default: automatic michael@0: // michael@0: // We use 0 as the default value so unitless values can be ignored. michael@0: // As a minimum, negative values can be ignored. michael@0: // michael@0: nsAutoString value; michael@0: if (tag != nsGkAtoms::msup_) { michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::subscriptshift_, value); michael@0: if (!value.IsEmpty()) { michael@0: ParseNumericValue(value, &subScriptShift, 0, PresContext(), michael@0: mStyleContext); michael@0: } michael@0: } michael@0: // superscriptshift michael@0: // michael@0: // "Specifies the minimum amount to shift the baseline of superscript up; the michael@0: // default is for the rendering agent to use its own positioning rules." michael@0: // michael@0: // values: length michael@0: // default: automatic michael@0: // michael@0: // We use 0 as the default value so unitless values can be ignored. michael@0: // As a minimum, negative values can be ignored. michael@0: // michael@0: if (tag != nsGkAtoms::msub_) { michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value); michael@0: if (!value.IsEmpty()) { michael@0: ParseNumericValue(value, &supScriptShift, 0, PresContext(), michael@0: mStyleContext); michael@0: } michael@0: } michael@0: // scriptspace from TeX for extra spacing after sup/subscript michael@0: // (0.5pt in plain TeX) michael@0: nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); michael@0: michael@0: return PlaceMultiScript(PresContext(), aRenderingContext, aPlaceOrigin, michael@0: aDesiredSize, this, subScriptShift, supScriptShift, michael@0: scriptSpace); michael@0: } michael@0: michael@0: // exported routine that both munderover and mmultiscripts share. michael@0: // munderover uses this when movablelimits is set. michael@0: nsresult michael@0: nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext* aPresContext, michael@0: nsRenderingContext& aRenderingContext, michael@0: bool aPlaceOrigin, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: nsMathMLContainerFrame* aFrame, michael@0: nscoord aUserSubScriptShift, michael@0: nscoord aUserSupScriptShift, michael@0: nscoord aScriptSpace) michael@0: { michael@0: nsIAtom* tag = aFrame->GetContent()->Tag(); michael@0: michael@0: // This function deals with both munderover etc. as well as msubsup etc. michael@0: // As the former behaves identically to the later, we treat it as such michael@0: // to avoid additional checks later. michael@0: if (tag == nsGkAtoms::mover_) michael@0: tag = nsGkAtoms::msup_; michael@0: else if (tag == nsGkAtoms::munder_) michael@0: tag = nsGkAtoms::msub_; michael@0: else if (tag == nsGkAtoms::munderover_) michael@0: tag = nsGkAtoms::msubsup_; michael@0: michael@0: nsBoundingMetrics bmFrame; michael@0: michael@0: nscoord minShiftFromXHeight, subDrop, supDrop; michael@0: michael@0: //////////////////////////////////////// michael@0: // Initialize super/sub shifts that michael@0: // depend only on the current font michael@0: //////////////////////////////////////// michael@0: michael@0: nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild(); michael@0: michael@0: if (!baseFrame) { michael@0: if (tag == nsGkAtoms::mmultiscripts_) michael@0: aFrame->ReportErrorToConsole("NoBase"); michael@0: else michael@0: aFrame->ReportChildCountError(); michael@0: return aFrame->ReflowError(aRenderingContext, aDesiredSize); michael@0: } michael@0: michael@0: michael@0: // get x-height (an ex) michael@0: const nsStyleFont* font = aFrame->StyleFont(); michael@0: nsRefPtr fm; michael@0: nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm)); michael@0: aRenderingContext.SetFont(fm); michael@0: michael@0: nscoord xHeight = fm->XHeight(); michael@0: michael@0: nscoord ruleSize; michael@0: GetRuleThickness (aRenderingContext, fm, ruleSize); michael@0: michael@0: // force the scriptSpace to be at least 1 pixel michael@0: nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); michael@0: aScriptSpace = std::max(onePixel, aScriptSpace); michael@0: michael@0: ///////////////////////////////////// michael@0: // first the shift for the subscript michael@0: michael@0: // subScriptShift{1,2} michael@0: // = minimum amount to shift the subscript down michael@0: // = sub{1,2} in TeXbook michael@0: // subScriptShift1 = subscriptshift attribute * x-height michael@0: nscoord subScriptShift1, subScriptShift2; michael@0: michael@0: // Get subScriptShift{1,2} default from font michael@0: GetSubScriptShifts (fm, subScriptShift1, subScriptShift2); michael@0: nscoord subScriptShift; michael@0: if (tag == nsGkAtoms::msub_) { michael@0: subScriptShift = subScriptShift1; michael@0: } else { michael@0: subScriptShift = std::max(subScriptShift1, subScriptShift2); michael@0: } michael@0: if (0 < aUserSubScriptShift) { michael@0: // the user has set the subscriptshift attribute michael@0: subScriptShift = std::max(subScriptShift, aUserSubScriptShift); michael@0: } michael@0: michael@0: ///////////////////////////////////// michael@0: // next the shift for the superscript michael@0: michael@0: // supScriptShift{1,2,3} michael@0: // = minimum amount to shift the supscript up michael@0: // = sup{1,2,3} in TeX michael@0: // supScriptShift1 = superscriptshift attribute * x-height michael@0: // Note that there are THREE values for supscript shifts depending michael@0: // on the current style michael@0: nscoord supScriptShift1, supScriptShift2, supScriptShift3; michael@0: // Set supScriptShift{1,2,3} default from font michael@0: GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3); michael@0: michael@0: // get sup script shift depending on current script level and display style michael@0: // Rule 18c, App. G, TeXbook michael@0: nsPresentationData presentationData; michael@0: aFrame->GetPresentationData(presentationData); michael@0: nscoord supScriptShift; michael@0: if (font->mScriptLevel == 0 && michael@0: font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK && michael@0: !NS_MATHML_IS_COMPRESSED(presentationData.flags)) { michael@0: // Style D in TeXbook michael@0: supScriptShift = supScriptShift1; michael@0: } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) { michael@0: // Style C' in TeXbook = D',T',S',SS' michael@0: supScriptShift = supScriptShift3; michael@0: } else { michael@0: // everything else = T,S,SS michael@0: supScriptShift = supScriptShift2; michael@0: } michael@0: michael@0: if (0 < aUserSupScriptShift) { michael@0: // the user has set the supscriptshift attribute michael@0: supScriptShift = std::max(supScriptShift, aUserSupScriptShift); michael@0: } michael@0: michael@0: //////////////////////////////////// michael@0: // Get the children's sizes michael@0: //////////////////////////////////// michael@0: michael@0: const WritingMode wm(aDesiredSize.GetWritingMode()); michael@0: nscoord width = 0, prescriptsWidth = 0, rightBearing = 0; michael@0: nscoord minSubScriptShift = 0, minSupScriptShift = 0; michael@0: nscoord trySubScriptShift = subScriptShift; michael@0: nscoord trySupScriptShift = supScriptShift; michael@0: nscoord maxSubScriptShift = subScriptShift; michael@0: nscoord maxSupScriptShift = supScriptShift; michael@0: nsHTMLReflowMetrics baseSize(wm); michael@0: nsHTMLReflowMetrics subScriptSize(wm); michael@0: nsHTMLReflowMetrics supScriptSize(wm); michael@0: nsHTMLReflowMetrics multiSubSize(wm), multiSupSize(wm); michael@0: baseFrame = nullptr; michael@0: nsIFrame* subScriptFrame = nullptr; michael@0: nsIFrame* supScriptFrame = nullptr; michael@0: nsIFrame* prescriptsFrame = nullptr; // frame of , if there. michael@0: michael@0: bool firstPrescriptsPair = false; michael@0: nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup; michael@0: multiSubSize.SetTopAscent(-0x7FFFFFFF); michael@0: multiSupSize.SetTopAscent(-0x7FFFFFFF); michael@0: bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF; michael@0: bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF; michael@0: nscoord italicCorrection = 0; michael@0: michael@0: nsBoundingMetrics boundingMetrics; michael@0: boundingMetrics.width = 0; michael@0: boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF; michael@0: aDesiredSize.Width() = aDesiredSize.Height() = 0; michael@0: michael@0: int32_t count = 0; michael@0: bool foundNoneTag = false; michael@0: michael@0: // Boolean to determine whether the current child is a subscript. michael@0: // Note that only msup starts with a superscript. michael@0: bool isSubScript = (tag != nsGkAtoms::msup_); michael@0: michael@0: nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); michael@0: while (childFrame) { michael@0: nsIAtom* childTag = childFrame->GetContent()->Tag(); michael@0: if (childTag == nsGkAtoms::mprescripts_) { michael@0: if (tag != nsGkAtoms::mmultiscripts_) { michael@0: if (aPlaceOrigin) { michael@0: aFrame->ReportInvalidChildError(childTag); michael@0: } michael@0: return aFrame->ReflowError(aRenderingContext, aDesiredSize); michael@0: } michael@0: if (prescriptsFrame) { michael@0: // duplicate found michael@0: // report an error, encourage people to get their markups in order michael@0: if (aPlaceOrigin) { michael@0: aFrame->ReportErrorToConsole("DuplicateMprescripts"); michael@0: } michael@0: return aFrame->ReflowError(aRenderingContext, aDesiredSize); michael@0: } michael@0: if (!isSubScript) { michael@0: if (aPlaceOrigin) { michael@0: aFrame->ReportErrorToConsole("SubSupMismatch"); michael@0: } michael@0: return aFrame->ReflowError(aRenderingContext, aDesiredSize); michael@0: } michael@0: michael@0: prescriptsFrame = childFrame; michael@0: firstPrescriptsPair = true; michael@0: } else if (0 == count) { michael@0: // base michael@0: michael@0: if (childTag == nsGkAtoms::none) { michael@0: if (tag == nsGkAtoms::mmultiscripts_) { michael@0: if (aPlaceOrigin) { michael@0: aFrame->ReportErrorToConsole("NoBase"); michael@0: } michael@0: return aFrame->ReflowError(aRenderingContext, aDesiredSize); michael@0: } else { michael@0: //A different error message is triggered later for the other tags michael@0: foundNoneTag = true; michael@0: } michael@0: } michael@0: baseFrame = childFrame; michael@0: GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); michael@0: michael@0: if (tag != nsGkAtoms::msub_) { michael@0: // Apply italics correction if there is the potential for a michael@0: // postsupscript. michael@0: GetItalicCorrection(bmBase, italicCorrection); michael@0: // If italics correction is applied, we always add "a little to spare" michael@0: // (see TeXbook Ch.11, p.64), as we estimate the italic creation michael@0: // ourselves and it isn't the same as TeX. michael@0: italicCorrection += onePixel; michael@0: } michael@0: michael@0: // we update boundingMetrics.{ascent,descent} with that michael@0: // of the baseFrame only after processing all the sup/sub pairs michael@0: boundingMetrics.width = bmBase.width; michael@0: boundingMetrics.rightBearing = bmBase.rightBearing; michael@0: boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten michael@0: } else { michael@0: // super/subscript block michael@0: if ( childTag == nsGkAtoms::none) { michael@0: foundNoneTag = true; michael@0: } michael@0: michael@0: if (isSubScript) { michael@0: // subscript michael@0: subScriptFrame = childFrame; michael@0: GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); michael@0: // get the subdrop from the subscript font michael@0: GetSubDropFromChild (subScriptFrame, subDrop); michael@0: // parameter v, Rule 18a, App. G, TeXbook michael@0: minSubScriptShift = bmBase.descent + subDrop; michael@0: trySubScriptShift = std::max(minSubScriptShift,subScriptShift); michael@0: multiSubSize.SetTopAscent(std::max(multiSubSize.TopAscent(), michael@0: subScriptSize.TopAscent())); michael@0: bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent); michael@0: bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent); michael@0: multiSubSize.Height() = michael@0: std::max(multiSubSize.Height(), michael@0: subScriptSize.Height() - subScriptSize.TopAscent()); michael@0: if (bmSubScript.width) michael@0: width = bmSubScript.width + aScriptSpace; michael@0: rightBearing = bmSubScript.rightBearing; michael@0: michael@0: if (tag == nsGkAtoms::msub_) { michael@0: boundingMetrics.rightBearing = boundingMetrics.width + rightBearing; michael@0: boundingMetrics.width += width; michael@0: michael@0: // get min subscript shift limit from x-height michael@0: // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook michael@0: nscoord minShiftFromXHeight = (nscoord) michael@0: (bmSubScript.ascent - (4.0f/5.0f) * xHeight); michael@0: maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight); michael@0: michael@0: maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift); michael@0: trySubScriptShift = subScriptShift; michael@0: } michael@0: } else { michael@0: // supscript michael@0: supScriptFrame = childFrame; michael@0: GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); michael@0: // get the supdrop from the supscript font michael@0: GetSupDropFromChild (supScriptFrame, supDrop); michael@0: // parameter u, Rule 18a, App. G, TeXbook michael@0: minSupScriptShift = bmBase.ascent - supDrop; michael@0: // get min supscript shift limit from x-height michael@0: // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook michael@0: minShiftFromXHeight = NSToCoordRound michael@0: ((bmSupScript.descent + (1.0f/4.0f) * xHeight)); michael@0: trySupScriptShift = std::max(minSupScriptShift, michael@0: std::max(minShiftFromXHeight, michael@0: supScriptShift)); michael@0: multiSupSize.SetTopAscent(std::max(multiSupSize.TopAscent(), michael@0: supScriptSize.TopAscent())); michael@0: bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent); michael@0: bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent); michael@0: multiSupSize.Height() = michael@0: std::max(multiSupSize.Height(), michael@0: supScriptSize.Height() - supScriptSize.TopAscent()); michael@0: michael@0: if (bmSupScript.width) michael@0: width = std::max(width, bmSupScript.width + aScriptSpace); michael@0: michael@0: if (!prescriptsFrame) { // we are still looping over base & postscripts michael@0: rightBearing = std::max(rightBearing, michael@0: italicCorrection + bmSupScript.rightBearing); michael@0: boundingMetrics.rightBearing = boundingMetrics.width + rightBearing; michael@0: boundingMetrics.width += width; michael@0: } else { michael@0: prescriptsWidth += width; michael@0: if (firstPrescriptsPair) { michael@0: firstPrescriptsPair = false; michael@0: boundingMetrics.leftBearing = michael@0: std::min(bmSubScript.leftBearing, bmSupScript.leftBearing); michael@0: } michael@0: } michael@0: width = rightBearing = 0; michael@0: michael@0: // negotiate between the various shifts so that michael@0: // there is enough gap between the sup and subscripts michael@0: // Rule 18e, App. G, TeXbook michael@0: if (tag == nsGkAtoms::mmultiscripts_ || michael@0: tag == nsGkAtoms::msubsup_) { michael@0: nscoord gap = michael@0: (trySupScriptShift - bmSupScript.descent) - michael@0: (bmSubScript.ascent - trySubScriptShift); michael@0: if (gap < 4.0f * ruleSize) { michael@0: // adjust trySubScriptShift to get a gap of (4.0 * ruleSize) michael@0: trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap); michael@0: } michael@0: michael@0: // next we want to ensure that the bottom of the superscript michael@0: // will be > (4/5) * x-height above baseline michael@0: gap = NSToCoordRound ((4.0f/5.0f) * xHeight - michael@0: (trySupScriptShift - bmSupScript.descent)); michael@0: if (gap > 0) { michael@0: trySupScriptShift += gap; michael@0: trySubScriptShift -= gap; michael@0: } michael@0: } michael@0: michael@0: maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift); michael@0: maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift); michael@0: michael@0: trySubScriptShift = subScriptShift; michael@0: trySupScriptShift = supScriptShift; michael@0: } michael@0: michael@0: isSubScript = !isSubScript; michael@0: } michael@0: count++; michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: michael@0: //NoBase error may also have been reported above michael@0: if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) || michael@0: (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame || michael@0: (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) || michael@0: (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) { michael@0: // report an error, encourage people to get their markups in order michael@0: if (aPlaceOrigin) { michael@0: if ((count != 2 && (tag == nsGkAtoms::msup_ || michael@0: tag == nsGkAtoms::msub_)) || michael@0: (count != 3 && tag == nsGkAtoms::msubsup_ )) { michael@0: aFrame->ReportChildCountError(); michael@0: } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) { michael@0: aFrame->ReportInvalidChildError(nsGkAtoms::none); michael@0: } else if (!baseFrame) { michael@0: aFrame->ReportErrorToConsole("NoBase"); michael@0: } else { michael@0: aFrame->ReportErrorToConsole("SubSupMismatch"); michael@0: } michael@0: } michael@0: return aFrame->ReflowError(aRenderingContext, aDesiredSize); michael@0: } michael@0: michael@0: // we left out the width of prescripts, so ... michael@0: boundingMetrics.rightBearing += prescriptsWidth; michael@0: boundingMetrics.width += prescriptsWidth; michael@0: michael@0: // Zero out the shifts in where a frame isn't present to avoid the potential michael@0: // for overflow. michael@0: if (!subScriptFrame) michael@0: maxSubScriptShift = 0; michael@0: if (!supScriptFrame) michael@0: maxSupScriptShift = 0; michael@0: michael@0: // we left out the base during our bounding box updates, so ... michael@0: if (tag == nsGkAtoms::msub_) { michael@0: boundingMetrics.ascent = std::max(bmBase.ascent, michael@0: bmMultiSub.ascent - maxSubScriptShift); michael@0: } else { michael@0: boundingMetrics.ascent = michael@0: std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift)); michael@0: } michael@0: if (tag == nsGkAtoms::msup_) { michael@0: boundingMetrics.descent = std::max(bmBase.descent, michael@0: bmMultiSup.descent - maxSupScriptShift); michael@0: } else { michael@0: boundingMetrics.descent = michael@0: std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift)); michael@0: } michael@0: aFrame->SetBoundingMetrics(boundingMetrics); michael@0: michael@0: // get the reflow metrics ... michael@0: aDesiredSize.SetTopAscent( michael@0: std::max(baseSize.TopAscent(), michael@0: std::max(multiSubSize.TopAscent() - maxSubScriptShift, michael@0: multiSupSize.TopAscent() + maxSupScriptShift))); michael@0: aDesiredSize.Height() = aDesiredSize.TopAscent() + michael@0: std::max(baseSize.Height() - baseSize.TopAscent(), michael@0: std::max(multiSubSize.Height() + maxSubScriptShift, michael@0: multiSupSize.Height() - maxSupScriptShift)); michael@0: aDesiredSize.Width() = boundingMetrics.width; michael@0: aDesiredSize.mBoundingMetrics = boundingMetrics; michael@0: michael@0: aFrame->SetReference(nsPoint(0, aDesiredSize.TopAscent())); michael@0: michael@0: ////////////////// michael@0: // Place Children michael@0: michael@0: // Place prescripts, followed by base, and then postscripts. michael@0: // The list of frames is in the order: {base} {postscripts} {prescripts} michael@0: // We go over the list in a circular manner, starting at michael@0: michael@0: if (aPlaceOrigin) { michael@0: nscoord dx = 0, dy = 0; michael@0: michael@0: // With msub and msup there is only one element and michael@0: // subscriptFrame/supScriptFrame have already been set above where michael@0: // relevant. In these cases we skip to the reflow part. michael@0: if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_) michael@0: count = 1; michael@0: else michael@0: count = 0; michael@0: childFrame = prescriptsFrame; michael@0: bool isPreScript = true; michael@0: do { michael@0: if (!childFrame) { // end of prescripts, michael@0: isPreScript = false; michael@0: // place the base ... michael@0: childFrame = baseFrame; michael@0: dy = aDesiredSize.TopAscent() - baseSize.TopAscent(); michael@0: FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr, michael@0: aFrame->MirrorIfRTL(aDesiredSize.Width(), michael@0: baseSize.Width(), michael@0: dx), michael@0: dy, 0); michael@0: dx += bmBase.width; michael@0: } else if (prescriptsFrame == childFrame) { michael@0: // Clear reflow flags of prescripts frame. michael@0: prescriptsFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); michael@0: } else { michael@0: // process each sup/sub pair michael@0: if (0 == count) { michael@0: subScriptFrame = childFrame; michael@0: count = 1; michael@0: } else if (1 == count) { michael@0: if (tag != nsGkAtoms::msub_) michael@0: supScriptFrame = childFrame; michael@0: count = 0; michael@0: michael@0: // get the ascent/descent of sup/subscripts stored in their rects michael@0: // rect.x = descent, rect.y = ascent michael@0: if (subScriptFrame) michael@0: GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); michael@0: if (supScriptFrame) michael@0: GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); michael@0: michael@0: width = std::max(subScriptSize.Width(), supScriptSize.Width()); michael@0: michael@0: if (subScriptFrame) { michael@0: nscoord x = dx; michael@0: // prescripts should be right aligned michael@0: // https://bugzilla.mozilla.org/show_bug.cgi?id=928675 michael@0: if (isPreScript) michael@0: x += width - subScriptSize.Width(); michael@0: dy = aDesiredSize.TopAscent() - subScriptSize.TopAscent() + michael@0: maxSubScriptShift; michael@0: FinishReflowChild (subScriptFrame, aPresContext, subScriptSize, michael@0: nullptr, michael@0: aFrame->MirrorIfRTL(aDesiredSize.Width(), michael@0: subScriptSize.Width(), michael@0: x), michael@0: dy, 0); michael@0: } michael@0: michael@0: if (supScriptFrame) { michael@0: nscoord x = dx; michael@0: if (isPreScript) { michael@0: x += width - supScriptSize.Width(); michael@0: } else { michael@0: // post superscripts are shifted by the italic correction value michael@0: x += italicCorrection; michael@0: } michael@0: dy = aDesiredSize.TopAscent() - supScriptSize.TopAscent() - michael@0: maxSupScriptShift; michael@0: FinishReflowChild (supScriptFrame, aPresContext, supScriptSize, michael@0: nullptr, michael@0: aFrame->MirrorIfRTL(aDesiredSize.Width(), michael@0: supScriptSize.Width(), michael@0: x), michael@0: dy, 0); michael@0: } michael@0: dx += width + aScriptSpace; michael@0: } michael@0: } michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } while (prescriptsFrame != childFrame); michael@0: } michael@0: michael@0: return NS_OK; michael@0: }