1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/mathml/nsMathMLmfencedFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,696 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#include "nsMathMLmfencedFrame.h" 1.11 +#include "nsRenderingContext.h" 1.12 +#include "nsMathMLChar.h" 1.13 +#include <algorithm> 1.14 + 1.15 +// 1.16 +// <mfenced> -- surround content with a pair of fences 1.17 +// 1.18 + 1.19 +nsIFrame* 1.20 +NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.21 +{ 1.22 + return new (aPresShell) nsMathMLmfencedFrame(aContext); 1.23 +} 1.24 + 1.25 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfencedFrame) 1.26 + 1.27 +nsMathMLmfencedFrame::~nsMathMLmfencedFrame() 1.28 +{ 1.29 + RemoveFencesAndSeparators(); 1.30 +} 1.31 + 1.32 +NS_IMETHODIMP 1.33 +nsMathMLmfencedFrame::InheritAutomaticData(nsIFrame* aParent) 1.34 +{ 1.35 + // let the base class get the default from our parent 1.36 + nsMathMLContainerFrame::InheritAutomaticData(aParent); 1.37 + 1.38 + mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; 1.39 + 1.40 + RemoveFencesAndSeparators(); 1.41 + CreateFencesAndSeparators(PresContext()); 1.42 + 1.43 + return NS_OK; 1.44 +} 1.45 + 1.46 +nsresult 1.47 +nsMathMLmfencedFrame::SetInitialChildList(ChildListID aListID, 1.48 + nsFrameList& aChildList) 1.49 +{ 1.50 + // First, let the base class do its work 1.51 + nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList); 1.52 + if (NS_FAILED(rv)) return rv; 1.53 + 1.54 + // InheritAutomaticData will not get called if our parent is not a mathml 1.55 + // frame, so initialize NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for 1.56 + // GetPreferredStretchSize() from Reflow(). 1.57 + mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; 1.58 + // No need to track the style contexts given to our MathML chars. 1.59 + // The Style System will use Get/SetAdditionalStyleContext() to keep them 1.60 + // up-to-date if dynamic changes arise. 1.61 + CreateFencesAndSeparators(PresContext()); 1.62 + return NS_OK; 1.63 +} 1.64 + 1.65 +nsresult 1.66 +nsMathMLmfencedFrame::AttributeChanged(int32_t aNameSpaceID, 1.67 + nsIAtom* aAttribute, 1.68 + int32_t aModType) 1.69 +{ 1.70 + RemoveFencesAndSeparators(); 1.71 + CreateFencesAndSeparators(PresContext()); 1.72 + 1.73 + return nsMathMLContainerFrame:: 1.74 + AttributeChanged(aNameSpaceID, aAttribute, aModType); 1.75 +} 1.76 + 1.77 +nsresult 1.78 +nsMathMLmfencedFrame::ChildListChanged(int32_t aModType) 1.79 +{ 1.80 + RemoveFencesAndSeparators(); 1.81 + CreateFencesAndSeparators(PresContext()); 1.82 + 1.83 + return nsMathMLContainerFrame::ChildListChanged(aModType); 1.84 +} 1.85 + 1.86 +void 1.87 +nsMathMLmfencedFrame::RemoveFencesAndSeparators() 1.88 +{ 1.89 + delete mOpenChar; 1.90 + delete mCloseChar; 1.91 + if (mSeparatorsChar) delete[] mSeparatorsChar; 1.92 + 1.93 + mOpenChar = nullptr; 1.94 + mCloseChar = nullptr; 1.95 + mSeparatorsChar = nullptr; 1.96 + mSeparatorsCount = 0; 1.97 +} 1.98 + 1.99 +void 1.100 +nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext) 1.101 +{ 1.102 + nsAutoString value; 1.103 + 1.104 + ////////////// 1.105 + // see if the opening fence is there ... 1.106 + if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::open, value)) { 1.107 + value = char16_t('('); // default as per the MathML REC 1.108 + } else { 1.109 + value.CompressWhitespace(); 1.110 + } 1.111 + 1.112 + if (!value.IsEmpty()) { 1.113 + mOpenChar = new nsMathMLChar; 1.114 + mOpenChar->SetData(aPresContext, value); 1.115 + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar); 1.116 + } 1.117 + 1.118 + ////////////// 1.119 + // see if the closing fence is there ... 1.120 + if(!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::close, value)) { 1.121 + value = char16_t(')'); // default as per the MathML REC 1.122 + } else { 1.123 + value.CompressWhitespace(); 1.124 + } 1.125 + 1.126 + if (!value.IsEmpty()) { 1.127 + mCloseChar = new nsMathMLChar; 1.128 + mCloseChar->SetData(aPresContext, value); 1.129 + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar); 1.130 + } 1.131 + 1.132 + ////////////// 1.133 + // see if separators are there ... 1.134 + if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separators_, value)) { 1.135 + value = char16_t(','); // default as per the MathML REC 1.136 + } else { 1.137 + value.StripWhitespace(); 1.138 + } 1.139 + 1.140 + mSeparatorsCount = value.Length(); 1.141 + if (0 < mSeparatorsCount) { 1.142 + int32_t sepCount = mFrames.GetLength() - 1; 1.143 + if (0 < sepCount) { 1.144 + mSeparatorsChar = new nsMathMLChar[sepCount]; 1.145 + nsAutoString sepChar; 1.146 + for (int32_t i = 0; i < sepCount; i++) { 1.147 + if (i < mSeparatorsCount) { 1.148 + sepChar = value[i]; 1.149 + } 1.150 + else { 1.151 + sepChar = value[mSeparatorsCount-1]; 1.152 + } 1.153 + mSeparatorsChar[i].SetData(aPresContext, sepChar); 1.154 + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i]); 1.155 + } 1.156 + mSeparatorsCount = sepCount; 1.157 + } else { 1.158 + // No separators. Note that sepCount can be -1 here, so don't 1.159 + // set mSeparatorsCount to it. 1.160 + mSeparatorsCount = 0; 1.161 + } 1.162 + } 1.163 +} 1.164 + 1.165 +void 1.166 +nsMathMLmfencedFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.167 + const nsRect& aDirtyRect, 1.168 + const nsDisplayListSet& aLists) 1.169 +{ 1.170 + ///////////// 1.171 + // display the content 1.172 + nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists); 1.173 + 1.174 + //////////// 1.175 + // display fences and separators 1.176 + uint32_t count = 0; 1.177 + if (mOpenChar) { 1.178 + mOpenChar->Display(aBuilder, this, aLists, count++); 1.179 + } 1.180 + 1.181 + if (mCloseChar) { 1.182 + mCloseChar->Display(aBuilder, this, aLists, count++); 1.183 + } 1.184 + 1.185 + for (int32_t i = 0; i < mSeparatorsCount; i++) { 1.186 + mSeparatorsChar[i].Display(aBuilder, this, aLists, count++); 1.187 + } 1.188 +} 1.189 + 1.190 +nsresult 1.191 +nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext, 1.192 + nsHTMLReflowMetrics& aDesiredSize, 1.193 + const nsHTMLReflowState& aReflowState, 1.194 + nsReflowStatus& aStatus) 1.195 +{ 1.196 + nsresult rv; 1.197 + aDesiredSize.Width() = aDesiredSize.Height() = 0; 1.198 + aDesiredSize.SetTopAscent(0); 1.199 + aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); 1.200 + 1.201 + int32_t i; 1.202 + const nsStyleFont* font = StyleFont(); 1.203 + nsRefPtr<nsFontMetrics> fm; 1.204 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); 1.205 + aReflowState.rendContext->SetFont(fm); 1.206 + nscoord axisHeight, em; 1.207 + GetAxisHeight(*aReflowState.rendContext, fm, axisHeight); 1.208 + GetEmHeight(fm, em); 1.209 + // leading to be left at the top and the bottom of stretched chars 1.210 + nscoord leading = NSToCoordRound(0.2f * em); 1.211 + 1.212 + ///////////// 1.213 + // Reflow children 1.214 + // Asking each child to cache its bounding metrics 1.215 + 1.216 + // Note that we don't use the base method nsMathMLContainerFrame::Reflow() 1.217 + // because we want to stretch our fences, separators and stretchy frames using 1.218 + // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base 1.219 + // method here, our stretchy frames will be stretched and placed, and we may 1.220 + // end up stretching our fences/separators with a different aDesiredSize. 1.221 + // XXX The above decision was revisited in bug 121748 and this code can be 1.222 + // refactored to use nsMathMLContainerFrame::Reflow() at some stage. 1.223 + 1.224 + nsReflowStatus childStatus; 1.225 + nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); 1.226 + nsIFrame* firstChild = GetFirstPrincipalChild(); 1.227 + nsIFrame* childFrame = firstChild; 1.228 + nscoord ascent = 0, descent = 0; 1.229 + if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) { 1.230 + // We use the ASCII metrics to get our minimum height. This way, 1.231 + // if we have borders or a background, they will fit better with 1.232 + // other elements on the line. 1.233 + ascent = fm->MaxAscent(); 1.234 + descent = fm->MaxDescent(); 1.235 + } 1.236 + while (childFrame) { 1.237 + nsHTMLReflowMetrics childDesiredSize(aReflowState, 1.238 + aDesiredSize.mFlags 1.239 + | NS_REFLOW_CALC_BOUNDING_METRICS); 1.240 + nsHTMLReflowState childReflowState(aPresContext, aReflowState, 1.241 + childFrame, availSize); 1.242 + rv = ReflowChild(childFrame, aPresContext, childDesiredSize, 1.243 + childReflowState, childStatus); 1.244 + //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); 1.245 + if (NS_FAILED(rv)) { 1.246 + // Call DidReflow() for the child frames we successfully did reflow. 1.247 + DidReflowChildren(firstChild, childFrame); 1.248 + return rv; 1.249 + } 1.250 + 1.251 + SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, 1.252 + childDesiredSize.mBoundingMetrics); 1.253 + 1.254 + nscoord childDescent = childDesiredSize.Height() - childDesiredSize.TopAscent(); 1.255 + if (descent < childDescent) 1.256 + descent = childDescent; 1.257 + if (ascent < childDesiredSize.TopAscent()) 1.258 + ascent = childDesiredSize.TopAscent(); 1.259 + 1.260 + childFrame = childFrame->GetNextSibling(); 1.261 + } 1.262 + 1.263 + ///////////// 1.264 + // Ask stretchy children to stretch themselves 1.265 + 1.266 + nsBoundingMetrics containerSize; 1.267 + nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; 1.268 + 1.269 + GetPreferredStretchSize(*aReflowState.rendContext, 1.270 + 0, /* i.e., without embellishments */ 1.271 + stretchDir, containerSize); 1.272 + childFrame = firstChild; 1.273 + while (childFrame) { 1.274 + nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame); 1.275 + if (mathmlChild) { 1.276 + nsHTMLReflowMetrics childDesiredSize(aReflowState); 1.277 + // retrieve the metrics that was stored at the previous pass 1.278 + GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize, 1.279 + childDesiredSize.mBoundingMetrics); 1.280 + 1.281 + mathmlChild->Stretch(*aReflowState.rendContext, 1.282 + stretchDir, containerSize, childDesiredSize); 1.283 + // store the updated metrics 1.284 + SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, 1.285 + childDesiredSize.mBoundingMetrics); 1.286 + 1.287 + nscoord childDescent = childDesiredSize.Height() - childDesiredSize.TopAscent(); 1.288 + if (descent < childDescent) 1.289 + descent = childDescent; 1.290 + if (ascent < childDesiredSize.TopAscent()) 1.291 + ascent = childDesiredSize.TopAscent(); 1.292 + } 1.293 + childFrame = childFrame->GetNextSibling(); 1.294 + } 1.295 + 1.296 + // bug 121748: for surrounding fences & separators, use a size that covers everything 1.297 + GetPreferredStretchSize(*aReflowState.rendContext, 1.298 + STRETCH_CONSIDER_EMBELLISHMENTS, 1.299 + stretchDir, containerSize); 1.300 + 1.301 + ////////////////////////////////////////// 1.302 + // Prepare the opening fence, separators, and closing fence, and 1.303 + // adjust the origin of children. 1.304 + 1.305 + // we need to center around the axis 1.306 + nscoord delta = std::max(containerSize.ascent - axisHeight, 1.307 + containerSize.descent + axisHeight); 1.308 + containerSize.ascent = delta + axisHeight; 1.309 + containerSize.descent = delta - axisHeight; 1.310 + 1.311 + bool isRTL = StyleVisibility()->mDirection; 1.312 + 1.313 + ///////////////// 1.314 + // opening fence ... 1.315 + ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar, 1.316 + NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, 1.317 + axisHeight, leading, em, containerSize, ascent, descent, isRTL); 1.318 + ///////////////// 1.319 + // separators ... 1.320 + for (i = 0; i < mSeparatorsCount; i++) { 1.321 + ReflowChar(aPresContext, *aReflowState.rendContext, &mSeparatorsChar[i], 1.322 + NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, 1.323 + axisHeight, leading, em, containerSize, ascent, descent, isRTL); 1.324 + } 1.325 + ///////////////// 1.326 + // closing fence ... 1.327 + ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar, 1.328 + NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, 1.329 + axisHeight, leading, em, containerSize, ascent, descent, isRTL); 1.330 + 1.331 + ////////////////// 1.332 + // Adjust the origins of each child. 1.333 + // and update our bounding metrics 1.334 + 1.335 + i = 0; 1.336 + nscoord dx = 0; 1.337 + nsBoundingMetrics bm; 1.338 + bool firstTime = true; 1.339 + nsMathMLChar *leftChar, *rightChar; 1.340 + if (isRTL) { 1.341 + leftChar = mCloseChar; 1.342 + rightChar = mOpenChar; 1.343 + } else { 1.344 + leftChar = mOpenChar; 1.345 + rightChar = mCloseChar; 1.346 + } 1.347 + 1.348 + if (leftChar) { 1.349 + PlaceChar(leftChar, ascent, bm, dx); 1.350 + aDesiredSize.mBoundingMetrics = bm; 1.351 + firstTime = false; 1.352 + } 1.353 + 1.354 + if (isRTL) { 1.355 + childFrame = this->GetLastChild(nsIFrame::kPrincipalList); 1.356 + } else { 1.357 + childFrame = firstChild; 1.358 + } 1.359 + while (childFrame) { 1.360 + nsHTMLReflowMetrics childSize(aReflowState); 1.361 + GetReflowAndBoundingMetricsFor(childFrame, childSize, bm); 1.362 + if (firstTime) { 1.363 + firstTime = false; 1.364 + aDesiredSize.mBoundingMetrics = bm; 1.365 + } 1.366 + else 1.367 + aDesiredSize.mBoundingMetrics += bm; 1.368 + 1.369 + FinishReflowChild(childFrame, aPresContext, childSize, nullptr, 1.370 + dx, ascent - childSize.TopAscent(), 0); 1.371 + dx += childSize.Width(); 1.372 + 1.373 + if (i < mSeparatorsCount) { 1.374 + PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i], 1.375 + ascent, bm, dx); 1.376 + aDesiredSize.mBoundingMetrics += bm; 1.377 + } 1.378 + i++; 1.379 + 1.380 + if (isRTL) { 1.381 + childFrame = childFrame->GetPrevSibling(); 1.382 + } else { 1.383 + childFrame = childFrame->GetNextSibling(); 1.384 + } 1.385 + } 1.386 + 1.387 + if (rightChar) { 1.388 + PlaceChar(rightChar, ascent, bm, dx); 1.389 + if (firstTime) 1.390 + aDesiredSize.mBoundingMetrics = bm; 1.391 + else 1.392 + aDesiredSize.mBoundingMetrics += bm; 1.393 + } 1.394 + 1.395 + aDesiredSize.Width() = aDesiredSize.mBoundingMetrics.width; 1.396 + aDesiredSize.Height() = ascent + descent; 1.397 + aDesiredSize.SetTopAscent(ascent); 1.398 + 1.399 + SetBoundingMetrics(aDesiredSize.mBoundingMetrics); 1.400 + SetReference(nsPoint(0, aDesiredSize.TopAscent())); 1.401 + 1.402 + // see if we should fix the spacing 1.403 + FixInterFrameSpacing(aDesiredSize); 1.404 + 1.405 + // Finished with these: 1.406 + ClearSavedChildMetrics(); 1.407 + 1.408 + // Set our overflow area 1.409 + GatherAndStoreOverflow(&aDesiredSize); 1.410 + 1.411 + aStatus = NS_FRAME_COMPLETE; 1.412 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.413 + return NS_OK; 1.414 +} 1.415 + 1.416 +static void 1.417 +GetCharSpacing(nsMathMLChar* aMathMLChar, 1.418 + nsOperatorFlags aForm, 1.419 + int32_t aScriptLevel, 1.420 + nscoord em, 1.421 + nscoord& aLeftSpace, 1.422 + nscoord& aRightSpace) 1.423 +{ 1.424 + nsAutoString data; 1.425 + aMathMLChar->GetData(data); 1.426 + nsOperatorFlags flags = 0; 1.427 + float lspace = 0.0f; 1.428 + float rspace = 0.0f; 1.429 + bool found = nsMathMLOperators::LookupOperator(data, aForm, 1.430 + &flags, &lspace, &rspace); 1.431 + 1.432 + // We don't want extra space when we are a script 1.433 + if (found && aScriptLevel > 0) { 1.434 + lspace /= 2.0f; 1.435 + rspace /= 2.0f; 1.436 + } 1.437 + 1.438 + aLeftSpace = NSToCoordRound(lspace * em); 1.439 + aRightSpace = NSToCoordRound(rspace * em); 1.440 +} 1.441 + 1.442 +// helper functions to perform the common task of formatting our chars 1.443 +/*static*/ nsresult 1.444 +nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext, 1.445 + nsRenderingContext& aRenderingContext, 1.446 + nsMathMLChar* aMathMLChar, 1.447 + nsOperatorFlags aForm, 1.448 + int32_t aScriptLevel, 1.449 + nscoord axisHeight, 1.450 + nscoord leading, 1.451 + nscoord em, 1.452 + nsBoundingMetrics& aContainerSize, 1.453 + nscoord& aAscent, 1.454 + nscoord& aDescent, 1.455 + bool aRTL) 1.456 +{ 1.457 + if (aMathMLChar && 0 < aMathMLChar->Length()) { 1.458 + nscoord leftSpace; 1.459 + nscoord rightSpace; 1.460 + GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace); 1.461 + 1.462 + // stretch the char to the appropriate height if it is not big enough. 1.463 + nsBoundingMetrics charSize; 1.464 + nsresult res = aMathMLChar->Stretch(aPresContext, aRenderingContext, 1.465 + NS_STRETCH_DIRECTION_VERTICAL, 1.466 + aContainerSize, charSize, 1.467 + NS_STRETCH_NORMAL, aRTL); 1.468 + 1.469 + if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) { 1.470 + // has changed... so center the char around the axis 1.471 + nscoord height = charSize.ascent + charSize.descent; 1.472 + charSize.ascent = height/2 + axisHeight; 1.473 + charSize.descent = height - charSize.ascent; 1.474 + } 1.475 + else { 1.476 + // either it hasn't changed or stretching the char failed (i.e., 1.477 + // GetBoundingMetrics failed) 1.478 + leading = 0; 1.479 + if (NS_FAILED(res)) { 1.480 + nsAutoString data; 1.481 + aMathMLChar->GetData(data); 1.482 + nsBoundingMetrics metrics = 1.483 + aRenderingContext.GetBoundingMetrics(data.get(), data.Length()); 1.484 + charSize.ascent = metrics.ascent; 1.485 + charSize.descent = metrics.descent; 1.486 + charSize.width = metrics.width; 1.487 + // Set this as the bounding metrics of the MathMLChar to leave 1.488 + // the necessary room to paint the char. 1.489 + aMathMLChar->SetBoundingMetrics(charSize); 1.490 + } 1.491 + } 1.492 + 1.493 + if (aAscent < charSize.ascent + leading) 1.494 + aAscent = charSize.ascent + leading; 1.495 + if (aDescent < charSize.descent + leading) 1.496 + aDescent = charSize.descent + leading; 1.497 + 1.498 + // account the spacing 1.499 + charSize.width += leftSpace + rightSpace; 1.500 + 1.501 + // x-origin is used to store lspace ... 1.502 + // y-origin is used to stored the ascent ... 1.503 + aMathMLChar->SetRect(nsRect(leftSpace, 1.504 + charSize.ascent, charSize.width, 1.505 + charSize.ascent + charSize.descent)); 1.506 + } 1.507 + return NS_OK; 1.508 +} 1.509 + 1.510 +/*static*/ void 1.511 +nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar, 1.512 + nscoord aDesiredAscent, 1.513 + nsBoundingMetrics& bm, 1.514 + nscoord& dx) 1.515 +{ 1.516 + aMathMLChar->GetBoundingMetrics(bm); 1.517 + 1.518 + // the char's x-origin was used to store lspace ... 1.519 + // the char's y-origin was used to store the ascent ... 1.520 + // the char's width was used to store the advance with (with spacing) ... 1.521 + nsRect rect; 1.522 + aMathMLChar->GetRect(rect); 1.523 + 1.524 + nscoord dy = aDesiredAscent - rect.y; 1.525 + if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) { 1.526 + // the stretchy char will be centered around the axis 1.527 + // so we adjust the returned bounding metrics accordingly 1.528 + bm.descent = (bm.ascent + bm.descent) - rect.y; 1.529 + bm.ascent = rect.y; 1.530 + } 1.531 + 1.532 + aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height)); 1.533 + 1.534 + bm.leftBearing += rect.x; 1.535 + bm.rightBearing += rect.x; 1.536 + 1.537 + // return rect.width since it includes lspace and rspace 1.538 + bm.width = rect.width; 1.539 + dx += rect.width; 1.540 +} 1.541 + 1.542 +static nscoord 1.543 +GetMaxCharWidth(nsPresContext* aPresContext, 1.544 + nsRenderingContext* aRenderingContext, 1.545 + nsMathMLChar* aMathMLChar, 1.546 + nsOperatorFlags aForm, 1.547 + int32_t aScriptLevel, 1.548 + nscoord em) 1.549 +{ 1.550 + nscoord width = aMathMLChar->GetMaxWidth(aPresContext, *aRenderingContext); 1.551 + 1.552 + if (0 < aMathMLChar->Length()) { 1.553 + nscoord leftSpace; 1.554 + nscoord rightSpace; 1.555 + GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace); 1.556 + 1.557 + width += leftSpace + rightSpace; 1.558 + } 1.559 + 1.560 + return width; 1.561 +} 1.562 + 1.563 +/* virtual */ void 1.564 +nsMathMLmfencedFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize) 1.565 +{ 1.566 + nscoord width = 0; 1.567 + 1.568 + nsPresContext* presContext = PresContext(); 1.569 + const nsStyleFont* font = StyleFont(); 1.570 + nsRefPtr<nsFontMetrics> fm; 1.571 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); 1.572 + nscoord em; 1.573 + GetEmHeight(fm, em); 1.574 + 1.575 + if (mOpenChar) { 1.576 + width += 1.577 + GetMaxCharWidth(presContext, aRenderingContext, mOpenChar, 1.578 + NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em); 1.579 + } 1.580 + 1.581 + int32_t i = 0; 1.582 + nsIFrame* childFrame = GetFirstPrincipalChild(); 1.583 + while (childFrame) { 1.584 + // XXX This includes margin while Reflow currently doesn't consider 1.585 + // margin, so we may end up with too much space, but, with stretchy 1.586 + // characters, this is an approximation anyway. 1.587 + width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame, 1.588 + nsLayoutUtils::PREF_WIDTH); 1.589 + 1.590 + if (i < mSeparatorsCount) { 1.591 + width += 1.592 + GetMaxCharWidth(presContext, aRenderingContext, &mSeparatorsChar[i], 1.593 + NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em); 1.594 + } 1.595 + i++; 1.596 + 1.597 + childFrame = childFrame->GetNextSibling(); 1.598 + } 1.599 + 1.600 + if (mCloseChar) { 1.601 + width += 1.602 + GetMaxCharWidth(presContext, aRenderingContext, mCloseChar, 1.603 + NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em); 1.604 + } 1.605 + 1.606 + aDesiredSize.Width() = width; 1.607 + aDesiredSize.mBoundingMetrics.width = width; 1.608 + aDesiredSize.mBoundingMetrics.leftBearing = 0; 1.609 + aDesiredSize.mBoundingMetrics.rightBearing = width; 1.610 +} 1.611 + 1.612 +nscoord 1.613 +nsMathMLmfencedFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize) 1.614 +{ 1.615 + nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize); 1.616 + if (!gap) return 0; 1.617 + 1.618 + nsRect rect; 1.619 + if (mOpenChar) { 1.620 + mOpenChar->GetRect(rect); 1.621 + rect.MoveBy(gap, 0); 1.622 + mOpenChar->SetRect(rect); 1.623 + } 1.624 + if (mCloseChar) { 1.625 + mCloseChar->GetRect(rect); 1.626 + rect.MoveBy(gap, 0); 1.627 + mCloseChar->SetRect(rect); 1.628 + } 1.629 + for (int32_t i = 0; i < mSeparatorsCount; i++) { 1.630 + mSeparatorsChar[i].GetRect(rect); 1.631 + rect.MoveBy(gap, 0); 1.632 + mSeparatorsChar[i].SetRect(rect); 1.633 + } 1.634 + return gap; 1.635 +} 1.636 + 1.637 +// ---------------------- 1.638 +// the Style System will use these to pass the proper style context to our MathMLChar 1.639 +nsStyleContext* 1.640 +nsMathMLmfencedFrame::GetAdditionalStyleContext(int32_t aIndex) const 1.641 +{ 1.642 + int32_t openIndex = -1; 1.643 + int32_t closeIndex = -1; 1.644 + int32_t lastIndex = mSeparatorsCount-1; 1.645 + 1.646 + if (mOpenChar) { 1.647 + lastIndex++; 1.648 + openIndex = lastIndex; 1.649 + } 1.650 + if (mCloseChar) { 1.651 + lastIndex++; 1.652 + closeIndex = lastIndex; 1.653 + } 1.654 + if (aIndex < 0 || aIndex > lastIndex) { 1.655 + return nullptr; 1.656 + } 1.657 + 1.658 + if (aIndex < mSeparatorsCount) { 1.659 + return mSeparatorsChar[aIndex].GetStyleContext(); 1.660 + } 1.661 + else if (aIndex == openIndex) { 1.662 + return mOpenChar->GetStyleContext(); 1.663 + } 1.664 + else if (aIndex == closeIndex) { 1.665 + return mCloseChar->GetStyleContext(); 1.666 + } 1.667 + return nullptr; 1.668 +} 1.669 + 1.670 +void 1.671 +nsMathMLmfencedFrame::SetAdditionalStyleContext(int32_t aIndex, 1.672 + nsStyleContext* aStyleContext) 1.673 +{ 1.674 + int32_t openIndex = -1; 1.675 + int32_t closeIndex = -1; 1.676 + int32_t lastIndex = mSeparatorsCount-1; 1.677 + 1.678 + if (mOpenChar) { 1.679 + lastIndex++; 1.680 + openIndex = lastIndex; 1.681 + } 1.682 + if (mCloseChar) { 1.683 + lastIndex++; 1.684 + closeIndex = lastIndex; 1.685 + } 1.686 + if (aIndex < 0 || aIndex > lastIndex) { 1.687 + return; 1.688 + } 1.689 + 1.690 + if (aIndex < mSeparatorsCount) { 1.691 + mSeparatorsChar[aIndex].SetStyleContext(aStyleContext); 1.692 + } 1.693 + else if (aIndex == openIndex) { 1.694 + mOpenChar->SetStyleContext(aStyleContext); 1.695 + } 1.696 + else if (aIndex == closeIndex) { 1.697 + mCloseChar->SetStyleContext(aStyleContext); 1.698 + } 1.699 +}