1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/mathml/nsMathMLContainerFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1617 @@ 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 +#include "nsMathMLContainerFrame.h" 1.10 +#include "nsPresContext.h" 1.11 +#include "nsIPresShell.h" 1.12 +#include "nsStyleContext.h" 1.13 +#include "nsNameSpaceManager.h" 1.14 +#include "nsRenderingContext.h" 1.15 +#include "nsIDOMMutationEvent.h" 1.16 +#include "nsGkAtoms.h" 1.17 +#include "nsAutoPtr.h" 1.18 +#include "nsDisplayList.h" 1.19 +#include "nsIReflowCallback.h" 1.20 +#include "mozilla/Likely.h" 1.21 +#include "nsIScriptError.h" 1.22 +#include "nsContentUtils.h" 1.23 +#include "nsMathMLElement.h" 1.24 + 1.25 +using namespace mozilla; 1.26 + 1.27 +// 1.28 +// nsMathMLContainerFrame implementation 1.29 +// 1.30 + 1.31 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLContainerFrame) 1.32 + 1.33 +NS_QUERYFRAME_HEAD(nsMathMLContainerFrame) 1.34 + NS_QUERYFRAME_ENTRY(nsIMathMLFrame) 1.35 + NS_QUERYFRAME_ENTRY(nsMathMLContainerFrame) 1.36 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.37 + 1.38 +// ============================================================================= 1.39 + 1.40 +// error handlers 1.41 +// provide a feedback to the user when a frame with bad markup can not be rendered 1.42 +nsresult 1.43 +nsMathMLContainerFrame::ReflowError(nsRenderingContext& aRenderingContext, 1.44 + nsHTMLReflowMetrics& aDesiredSize) 1.45 +{ 1.46 + // clear all other flags and record that there is an error with this frame 1.47 + mEmbellishData.flags = 0; 1.48 + mPresentationData.flags = NS_MATHML_ERROR; 1.49 + 1.50 + /////////////// 1.51 + // Set font 1.52 + nsRefPtr<nsFontMetrics> fm; 1.53 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); 1.54 + aRenderingContext.SetFont(fm); 1.55 + 1.56 + // bounding metrics 1.57 + nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup"); 1.58 + mBoundingMetrics = 1.59 + aRenderingContext.GetBoundingMetrics(errorMsg.get(), errorMsg.Length()); 1.60 + 1.61 + // reflow metrics 1.62 + aDesiredSize.SetTopAscent(fm->MaxAscent()); 1.63 + nscoord descent = fm->MaxDescent(); 1.64 + aDesiredSize.Height() = aDesiredSize.TopAscent() + descent; 1.65 + aDesiredSize.Width() = mBoundingMetrics.width; 1.66 + 1.67 + // Also return our bounding metrics 1.68 + aDesiredSize.mBoundingMetrics = mBoundingMetrics; 1.69 + 1.70 + return NS_OK; 1.71 +} 1.72 + 1.73 +class nsDisplayMathMLError : public nsDisplayItem { 1.74 +public: 1.75 + nsDisplayMathMLError(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) 1.76 + : nsDisplayItem(aBuilder, aFrame) { 1.77 + MOZ_COUNT_CTOR(nsDisplayMathMLError); 1.78 + } 1.79 +#ifdef NS_BUILD_REFCNT_LOGGING 1.80 + virtual ~nsDisplayMathMLError() { 1.81 + MOZ_COUNT_DTOR(nsDisplayMathMLError); 1.82 + } 1.83 +#endif 1.84 + 1.85 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.86 + nsRenderingContext* aCtx) MOZ_OVERRIDE; 1.87 + NS_DISPLAY_DECL_NAME("MathMLError", TYPE_MATHML_ERROR) 1.88 +}; 1.89 + 1.90 +void nsDisplayMathMLError::Paint(nsDisplayListBuilder* aBuilder, 1.91 + nsRenderingContext* aCtx) 1.92 +{ 1.93 + // Set color and font ... 1.94 + nsRefPtr<nsFontMetrics> fm; 1.95 + nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm)); 1.96 + aCtx->SetFont(fm); 1.97 + 1.98 + nsPoint pt = ToReferenceFrame(); 1.99 + aCtx->SetColor(NS_RGB(255,0,0)); 1.100 + aCtx->FillRect(nsRect(pt, mFrame->GetSize())); 1.101 + aCtx->SetColor(NS_RGB(255,255,255)); 1.102 + 1.103 + nscoord ascent = aCtx->FontMetrics()->MaxAscent(); 1.104 + 1.105 + NS_NAMED_LITERAL_STRING(errorMsg, "invalid-markup"); 1.106 + aCtx->DrawString(errorMsg.get(), uint32_t(errorMsg.Length()), 1.107 + pt.x, pt.y+ascent); 1.108 +} 1.109 + 1.110 +/* ///////////// 1.111 + * nsIMathMLFrame - support methods for stretchy elements 1.112 + * ============================================================================= 1.113 + */ 1.114 + 1.115 +static bool 1.116 +IsForeignChild(const nsIFrame* aFrame) 1.117 +{ 1.118 + // This counts nsMathMLmathBlockFrame as a foreign child, because it 1.119 + // uses block reflow 1.120 + return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) || 1.121 + aFrame->GetType() == nsGkAtoms::blockFrame; 1.122 +} 1.123 + 1.124 +static void 1.125 +DestroyHTMLReflowMetrics(void *aPropertyValue) 1.126 +{ 1.127 + delete static_cast<nsHTMLReflowMetrics*>(aPropertyValue); 1.128 +} 1.129 + 1.130 +NS_DECLARE_FRAME_PROPERTY(HTMLReflowMetricsProperty, DestroyHTMLReflowMetrics) 1.131 + 1.132 +/* static */ void 1.133 +nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame* aFrame, 1.134 + const nsHTMLReflowMetrics& aReflowMetrics, 1.135 + const nsBoundingMetrics& aBoundingMetrics) 1.136 +{ 1.137 + nsHTMLReflowMetrics *metrics = new nsHTMLReflowMetrics(aReflowMetrics); 1.138 + metrics->mBoundingMetrics = aBoundingMetrics; 1.139 + aFrame->Properties().Set(HTMLReflowMetricsProperty(), metrics); 1.140 +} 1.141 + 1.142 +// helper method to facilitate getting the reflow and bounding metrics 1.143 +/* static */ void 1.144 +nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFrame, 1.145 + nsHTMLReflowMetrics& aReflowMetrics, 1.146 + nsBoundingMetrics& aBoundingMetrics, 1.147 + eMathMLFrameType* aMathMLFrameType) 1.148 +{ 1.149 + NS_PRECONDITION(aFrame, "null arg"); 1.150 + 1.151 + nsHTMLReflowMetrics *metrics = static_cast<nsHTMLReflowMetrics*> 1.152 + (aFrame->Properties().Get(HTMLReflowMetricsProperty())); 1.153 + 1.154 + // IMPORTANT: This function is only meant to be called in Place() methods 1.155 + // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the 1.156 + // information. 1.157 + NS_ASSERTION(metrics, "Didn't SaveReflowAndBoundingMetricsFor frame!"); 1.158 + if (metrics) { 1.159 + aReflowMetrics = *metrics; 1.160 + aBoundingMetrics = metrics->mBoundingMetrics; 1.161 + } 1.162 + 1.163 + if (aMathMLFrameType) { 1.164 + if (!IsForeignChild(aFrame)) { 1.165 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame); 1.166 + if (mathMLFrame) { 1.167 + *aMathMLFrameType = mathMLFrame->GetMathMLFrameType(); 1.168 + return; 1.169 + } 1.170 + } 1.171 + *aMathMLFrameType = eMathMLFrameType_UNKNOWN; 1.172 + } 1.173 + 1.174 +} 1.175 + 1.176 +void 1.177 +nsMathMLContainerFrame::ClearSavedChildMetrics() 1.178 +{ 1.179 + nsIFrame* childFrame = mFrames.FirstChild(); 1.180 + FramePropertyTable* props = PresContext()->PropertyTable(); 1.181 + while (childFrame) { 1.182 + props->Delete(childFrame, HTMLReflowMetricsProperty()); 1.183 + childFrame = childFrame->GetNextSibling(); 1.184 + } 1.185 +} 1.186 + 1.187 +// helper to get the preferred size that a container frame should use to fire 1.188 +// the stretch on its stretchy child frames. 1.189 +void 1.190 +nsMathMLContainerFrame::GetPreferredStretchSize(nsRenderingContext& aRenderingContext, 1.191 + uint32_t aOptions, 1.192 + nsStretchDirection aStretchDirection, 1.193 + nsBoundingMetrics& aPreferredStretchSize) 1.194 +{ 1.195 + if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) { 1.196 + // when our actual size is ok, just use it 1.197 + aPreferredStretchSize = mBoundingMetrics; 1.198 + } 1.199 + else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) { 1.200 + // compute our up-to-date size using Place() 1.201 + nsHTMLReflowMetrics metrics(GetWritingMode()); // ??? 1.202 + Place(aRenderingContext, false, metrics); 1.203 + aPreferredStretchSize = metrics.mBoundingMetrics; 1.204 + } 1.205 + else { 1.206 + // compute a size that doesn't include embellishements 1.207 + bool stretchAll = 1.208 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || 1.209 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags); 1.210 + NS_ASSERTION(NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) || 1.211 + stretchAll, 1.212 + "invalid call to GetPreferredStretchSize"); 1.213 + bool firstTime = true; 1.214 + nsBoundingMetrics bm, bmChild; 1.215 + nsIFrame* childFrame = 1.216 + stretchAll ? GetFirstPrincipalChild() : mPresentationData.baseFrame; 1.217 + while (childFrame) { 1.218 + // initializations in case this child happens not to be a MathML frame 1.219 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame); 1.220 + if (mathMLFrame) { 1.221 + nsEmbellishData embellishData; 1.222 + nsPresentationData presentationData; 1.223 + mathMLFrame->GetEmbellishData(embellishData); 1.224 + mathMLFrame->GetPresentationData(presentationData); 1.225 + if (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) && 1.226 + embellishData.direction == aStretchDirection && 1.227 + presentationData.baseFrame) { 1.228 + // embellishements are not included, only consider the inner first child itself 1.229 + // XXXkt Does that mean the core descendent frame should be used 1.230 + // instead of the base child? 1.231 + nsIMathMLFrame* mathMLchildFrame = do_QueryFrame(presentationData.baseFrame); 1.232 + if (mathMLchildFrame) { 1.233 + mathMLFrame = mathMLchildFrame; 1.234 + } 1.235 + } 1.236 + mathMLFrame->GetBoundingMetrics(bmChild); 1.237 + } 1.238 + else { 1.239 + nsHTMLReflowMetrics unused(GetWritingMode()); 1.240 + GetReflowAndBoundingMetricsFor(childFrame, unused, bmChild); 1.241 + } 1.242 + 1.243 + if (firstTime) { 1.244 + firstTime = false; 1.245 + bm = bmChild; 1.246 + if (!stretchAll) { 1.247 + // we may get here for cases such as <msup><mo>...</mo> ... </msup>, 1.248 + // or <maction>...<mo>...</mo></maction>. 1.249 + break; 1.250 + } 1.251 + } 1.252 + else { 1.253 + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) { 1.254 + // if we get here, it means this is container that will stack its children 1.255 + // vertically and fire an horizontal stretch on each them. This is the case 1.256 + // for \munder, \mover, \munderover. We just sum-up the size vertically. 1.257 + bm.descent += bmChild.ascent + bmChild.descent; 1.258 + // Sometimes non-spacing marks (when width is zero) are positioned 1.259 + // to the left of the origin, but it is the distance between left 1.260 + // and right bearing that is important rather than the offsets from 1.261 + // the origin. 1.262 + if (bmChild.width == 0) { 1.263 + bmChild.rightBearing -= bmChild.leftBearing; 1.264 + bmChild.leftBearing = 0; 1.265 + } 1.266 + if (bm.leftBearing > bmChild.leftBearing) 1.267 + bm.leftBearing = bmChild.leftBearing; 1.268 + if (bm.rightBearing < bmChild.rightBearing) 1.269 + bm.rightBearing = bmChild.rightBearing; 1.270 + } 1.271 + else if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)) { 1.272 + // just sum-up the sizes horizontally. 1.273 + bm += bmChild; 1.274 + } 1.275 + else { 1.276 + NS_ERROR("unexpected case in GetPreferredStretchSize"); 1.277 + break; 1.278 + } 1.279 + } 1.280 + childFrame = childFrame->GetNextSibling(); 1.281 + } 1.282 + aPreferredStretchSize = bm; 1.283 + } 1.284 +} 1.285 + 1.286 +NS_IMETHODIMP 1.287 +nsMathMLContainerFrame::Stretch(nsRenderingContext& aRenderingContext, 1.288 + nsStretchDirection aStretchDirection, 1.289 + nsBoundingMetrics& aContainerSize, 1.290 + nsHTMLReflowMetrics& aDesiredStretchSize) 1.291 +{ 1.292 + if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) { 1.293 + 1.294 + if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) { 1.295 + NS_WARNING("it is wrong to fire stretch more than once on a frame"); 1.296 + return NS_OK; 1.297 + } 1.298 + mPresentationData.flags |= NS_MATHML_STRETCH_DONE; 1.299 + 1.300 + if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { 1.301 + NS_WARNING("it is wrong to fire stretch on a erroneous frame"); 1.302 + return NS_OK; 1.303 + } 1.304 + 1.305 + // Pass the stretch to the base child ... 1.306 + 1.307 + nsIFrame* baseFrame = mPresentationData.baseFrame; 1.308 + if (baseFrame) { 1.309 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(baseFrame); 1.310 + NS_ASSERTION(mathMLFrame, "Something is wrong somewhere"); 1.311 + if (mathMLFrame) { 1.312 + bool stretchAll = 1.313 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || 1.314 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags); 1.315 + 1.316 + // And the trick is that the child's rect.x is still holding the descent, 1.317 + // and rect.y is still holding the ascent ... 1.318 + nsHTMLReflowMetrics childSize(aDesiredStretchSize); 1.319 + GetReflowAndBoundingMetricsFor(baseFrame, childSize, childSize.mBoundingMetrics); 1.320 + 1.321 + // See if we should downsize and confine the stretch to us... 1.322 + // XXX there may be other cases where we can downsize the stretch, 1.323 + // e.g., the first ∑ might appear big in the following situation 1.324 + // <math xmlns='http://www.w3.org/1998/Math/MathML'> 1.325 + // <mstyle> 1.326 + // <msub> 1.327 + // <msub><mo>∑</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub> 1.328 + // <msub><mo>∑</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub> 1.329 + // </msub> 1.330 + // </mstyle> 1.331 + // </math> 1.332 + nsBoundingMetrics containerSize = aContainerSize; 1.333 + if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT && 1.334 + aStretchDirection != mEmbellishData.direction) { 1.335 + if (mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED) { 1.336 + containerSize = childSize.mBoundingMetrics; 1.337 + } 1.338 + else { 1.339 + GetPreferredStretchSize(aRenderingContext, 1.340 + stretchAll ? STRETCH_CONSIDER_EMBELLISHMENTS : 0, 1.341 + mEmbellishData.direction, containerSize); 1.342 + } 1.343 + } 1.344 + 1.345 + // do the stretching... 1.346 + mathMLFrame->Stretch(aRenderingContext, 1.347 + mEmbellishData.direction, containerSize, childSize); 1.348 + // store the updated metrics 1.349 + SaveReflowAndBoundingMetricsFor(baseFrame, childSize, 1.350 + childSize.mBoundingMetrics); 1.351 + 1.352 + // Remember the siblings which were _deferred_. 1.353 + // Now that this embellished child may have changed, we need to 1.354 + // fire the stretch on its siblings using our updated size 1.355 + 1.356 + if (stretchAll) { 1.357 + 1.358 + nsStretchDirection stretchDir = 1.359 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ? 1.360 + NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL; 1.361 + 1.362 + GetPreferredStretchSize(aRenderingContext, STRETCH_CONSIDER_EMBELLISHMENTS, 1.363 + stretchDir, containerSize); 1.364 + 1.365 + nsIFrame* childFrame = mFrames.FirstChild(); 1.366 + while (childFrame) { 1.367 + if (childFrame != mPresentationData.baseFrame) { 1.368 + mathMLFrame = do_QueryFrame(childFrame); 1.369 + if (mathMLFrame) { 1.370 + // retrieve the metrics that was stored at the previous pass 1.371 + GetReflowAndBoundingMetricsFor(childFrame, 1.372 + childSize, childSize.mBoundingMetrics); 1.373 + // do the stretching... 1.374 + mathMLFrame->Stretch(aRenderingContext, stretchDir, 1.375 + containerSize, childSize); 1.376 + // store the updated metrics 1.377 + SaveReflowAndBoundingMetricsFor(childFrame, childSize, 1.378 + childSize.mBoundingMetrics); 1.379 + } 1.380 + } 1.381 + childFrame = childFrame->GetNextSibling(); 1.382 + } 1.383 + } 1.384 + 1.385 + // re-position all our children 1.386 + nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize); 1.387 + if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { 1.388 + // Make sure the child frames get their DidReflow() calls. 1.389 + DidReflowChildren(mFrames.FirstChild()); 1.390 + } 1.391 + 1.392 + // If our parent is not embellished, it means we are the outermost embellished 1.393 + // container and so we put the spacing, otherwise we don't include the spacing, 1.394 + // the outermost embellished container will take care of it. 1.395 + 1.396 + nsEmbellishData parentData; 1.397 + GetEmbellishDataFrom(mParent, parentData); 1.398 + // ensure that we are the embellished child, not just a sibling 1.399 + // (need to test coreFrame since <mfrac> resets other things) 1.400 + if (parentData.coreFrame != mEmbellishData.coreFrame) { 1.401 + // (we fetch values from the core since they may use units that depend 1.402 + // on style data, and style changes could have occurred in the core since 1.403 + // our last visit there) 1.404 + nsEmbellishData coreData; 1.405 + GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData); 1.406 + 1.407 + mBoundingMetrics.width += 1.408 + coreData.leadingSpace + coreData.trailingSpace; 1.409 + aDesiredStretchSize.Width() = mBoundingMetrics.width; 1.410 + aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width; 1.411 + 1.412 + nscoord dx = (StyleVisibility()->mDirection ? 1.413 + coreData.trailingSpace : coreData.leadingSpace); 1.414 + if (dx != 0) { 1.415 + mBoundingMetrics.leftBearing += dx; 1.416 + mBoundingMetrics.rightBearing += dx; 1.417 + aDesiredStretchSize.mBoundingMetrics.leftBearing += dx; 1.418 + aDesiredStretchSize.mBoundingMetrics.rightBearing += dx; 1.419 + 1.420 + nsIFrame* childFrame = mFrames.FirstChild(); 1.421 + while (childFrame) { 1.422 + childFrame->SetPosition(childFrame->GetPosition() 1.423 + + nsPoint(dx, 0)); 1.424 + childFrame = childFrame->GetNextSibling(); 1.425 + } 1.426 + } 1.427 + } 1.428 + 1.429 + // Finished with these: 1.430 + ClearSavedChildMetrics(); 1.431 + // Set our overflow area 1.432 + GatherAndStoreOverflow(&aDesiredStretchSize); 1.433 + } 1.434 + } 1.435 + } 1.436 + return NS_OK; 1.437 +} 1.438 + 1.439 +nsresult 1.440 +nsMathMLContainerFrame::FinalizeReflow(nsRenderingContext& aRenderingContext, 1.441 + nsHTMLReflowMetrics& aDesiredSize) 1.442 +{ 1.443 + // During reflow, we use rect.x and rect.y as placeholders for the child's ascent 1.444 + // and descent in expectation of a stretch command. Hence we need to ensure that 1.445 + // a stretch command will actually be fired later on, after exiting from our 1.446 + // reflow. If the stretch is not fired, the rect.x, and rect.y will remain 1.447 + // with inappropriate data causing children to be improperly positioned. 1.448 + // This helper method checks to see if our parent will fire a stretch command 1.449 + // targeted at us. If not, we go ahead and fire an involutive stretch on 1.450 + // ourselves. This will clear all the rect.x and rect.y, and return our 1.451 + // desired size. 1.452 + 1.453 + 1.454 + // First, complete the post-reflow hook. 1.455 + // We use the information in our children rectangles to position them. 1.456 + // If placeOrigin==false, then Place() will not touch rect.x, and rect.y. 1.457 + // They will still be holding the ascent and descent for each child. 1.458 + 1.459 + // The first clause caters for any non-embellished container. 1.460 + // The second clause is for a container which won't fire stretch even though it is 1.461 + // embellished, e.g., as in <mfrac><mo>...</mo> ... </mfrac>, the test is convoluted 1.462 + // because it excludes the particular case of the core <mo>...</mo> itself. 1.463 + // (<mo> needs to fire stretch on its MathMLChar in any case to initialize it) 1.464 + bool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) || 1.465 + (mEmbellishData.coreFrame != this && !mPresentationData.baseFrame && 1.466 + mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED); 1.467 + nsresult rv = Place(aRenderingContext, placeOrigin, aDesiredSize); 1.468 + 1.469 + // Place() will call FinishReflowChild() when placeOrigin is true but if 1.470 + // it returns before reaching FinishReflowChild() due to errors we need 1.471 + // to fulfill the reflow protocol by calling DidReflow for the child frames 1.472 + // that still needs it here (or we may crash - bug 366012). 1.473 + // If placeOrigin is false we should reach Place() with aPlaceOrigin == true 1.474 + // through Stretch() eventually. 1.475 + if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { 1.476 + DidReflowChildren(GetFirstPrincipalChild()); 1.477 + return rv; 1.478 + } 1.479 + 1.480 + bool parentWillFireStretch = false; 1.481 + if (!placeOrigin) { 1.482 + // This means the rect.x and rect.y of our children were not set!! 1.483 + // Don't go without checking to see if our parent will later fire a Stretch() command 1.484 + // targeted at us. The Stretch() will cause the rect.x and rect.y to clear... 1.485 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(mParent); 1.486 + if (mathMLFrame) { 1.487 + nsEmbellishData embellishData; 1.488 + nsPresentationData presentationData; 1.489 + mathMLFrame->GetEmbellishData(embellishData); 1.490 + mathMLFrame->GetPresentationData(presentationData); 1.491 + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags) || 1.492 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(presentationData.flags) || 1.493 + (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) 1.494 + && presentationData.baseFrame == this)) 1.495 + { 1.496 + parentWillFireStretch = true; 1.497 + } 1.498 + } 1.499 + if (!parentWillFireStretch) { 1.500 + // There is nobody who will fire the stretch for us, we do it ourselves! 1.501 + 1.502 + bool stretchAll = 1.503 + /* NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || */ 1.504 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags); 1.505 + 1.506 + nsBoundingMetrics defaultSize; 1.507 + if (mEmbellishData.coreFrame == this /* case of a bare <mo>...</mo> itself */ 1.508 + || stretchAll) { /* or <mover><mo>...</mo>...</mover>, or friends */ 1.509 + // use our current size as computed earlier by Place() 1.510 + defaultSize = aDesiredSize.mBoundingMetrics; 1.511 + } 1.512 + else { /* case of <msup><mo>...</mo>...</msup> or friends */ 1.513 + // compute a size that doesn't include embellishments 1.514 + GetPreferredStretchSize(aRenderingContext, 0, mEmbellishData.direction, 1.515 + defaultSize); 1.516 + } 1.517 + Stretch(aRenderingContext, NS_STRETCH_DIRECTION_DEFAULT, defaultSize, 1.518 + aDesiredSize); 1.519 +#ifdef DEBUG 1.520 + { 1.521 + // The Place() call above didn't request FinishReflowChild(), 1.522 + // so let's check that we eventually did through Stretch(). 1.523 + nsIFrame* childFrame = GetFirstPrincipalChild(); 1.524 + for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { 1.525 + NS_ASSERTION(!(childFrame->GetStateBits() & NS_FRAME_IN_REFLOW), 1.526 + "DidReflow() was never called"); 1.527 + } 1.528 + } 1.529 +#endif 1.530 + } 1.531 + } 1.532 + 1.533 + // Also return our bounding metrics 1.534 + aDesiredSize.mBoundingMetrics = mBoundingMetrics; 1.535 + 1.536 + // see if we should fix the spacing 1.537 + FixInterFrameSpacing(aDesiredSize); 1.538 + 1.539 + if (!parentWillFireStretch) { 1.540 + // Not expecting a stretch. 1.541 + // Finished with these: 1.542 + ClearSavedChildMetrics(); 1.543 + // Set our overflow area. 1.544 + GatherAndStoreOverflow(&aDesiredSize); 1.545 + } 1.546 + 1.547 + return NS_OK; 1.548 +} 1.549 + 1.550 + 1.551 +/* ///////////// 1.552 + * nsIMathMLFrame - support methods for scripting elements (nested frames 1.553 + * within msub, msup, msubsup, munder, mover, munderover, mmultiscripts, 1.554 + * mfrac, mroot, mtable). 1.555 + * ============================================================================= 1.556 + */ 1.557 + 1.558 +// helper to let the update of presentation data pass through 1.559 +// a subtree that may contain non-mathml container frames 1.560 +/* static */ void 1.561 +nsMathMLContainerFrame::PropagatePresentationDataFor(nsIFrame* aFrame, 1.562 + uint32_t aFlagsValues, 1.563 + uint32_t aFlagsToUpdate) 1.564 +{ 1.565 + if (!aFrame || !aFlagsToUpdate) 1.566 + return; 1.567 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame); 1.568 + if (mathMLFrame) { 1.569 + // update 1.570 + mathMLFrame->UpdatePresentationData(aFlagsValues, 1.571 + aFlagsToUpdate); 1.572 + // propagate using the base method to make sure that the control 1.573 + // is passed on to MathML frames that may be overloading the method 1.574 + mathMLFrame->UpdatePresentationDataFromChildAt(0, -1, 1.575 + aFlagsValues, aFlagsToUpdate); 1.576 + } 1.577 + else { 1.578 + // propagate down the subtrees 1.579 + nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); 1.580 + while (childFrame) { 1.581 + PropagatePresentationDataFor(childFrame, 1.582 + aFlagsValues, aFlagsToUpdate); 1.583 + childFrame = childFrame->GetNextSibling(); 1.584 + } 1.585 + } 1.586 +} 1.587 + 1.588 +/* static */ void 1.589 +nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(nsIFrame* aParentFrame, 1.590 + int32_t aFirstChildIndex, 1.591 + int32_t aLastChildIndex, 1.592 + uint32_t aFlagsValues, 1.593 + uint32_t aFlagsToUpdate) 1.594 +{ 1.595 + if (!aParentFrame || !aFlagsToUpdate) 1.596 + return; 1.597 + int32_t index = 0; 1.598 + nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild(); 1.599 + while (childFrame) { 1.600 + if ((index >= aFirstChildIndex) && 1.601 + ((aLastChildIndex <= 0) || ((aLastChildIndex > 0) && 1.602 + (index <= aLastChildIndex)))) { 1.603 + PropagatePresentationDataFor(childFrame, 1.604 + aFlagsValues, aFlagsToUpdate); 1.605 + } 1.606 + index++; 1.607 + childFrame = childFrame->GetNextSibling(); 1.608 + } 1.609 +} 1.610 + 1.611 +/* ////////////////// 1.612 + * Frame construction 1.613 + * ============================================================================= 1.614 + */ 1.615 + 1.616 + 1.617 +void 1.618 +nsMathMLContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.619 + const nsRect& aDirtyRect, 1.620 + const nsDisplayListSet& aLists) 1.621 +{ 1.622 + // report an error if something wrong was found in this frame 1.623 + if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { 1.624 + if (!IsVisibleForPainting(aBuilder)) 1.625 + return; 1.626 + 1.627 + aLists.Content()->AppendNewToTop( 1.628 + new (aBuilder) nsDisplayMathMLError(aBuilder, this)); 1.629 + return; 1.630 + } 1.631 + 1.632 + DisplayBorderBackgroundOutline(aBuilder, aLists); 1.633 + 1.634 + BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists, 1.635 + DISPLAY_CHILD_INLINE); 1.636 + 1.637 +#if defined(DEBUG) && defined(SHOW_BOUNDING_BOX) 1.638 + // for visual debug 1.639 + // ---------------- 1.640 + // if you want to see your bounding box, make sure to properly fill 1.641 + // your mBoundingMetrics and mReference point, and set 1.642 + // mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS 1.643 + // in the Init() of your sub-class 1.644 + DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists); 1.645 +#endif 1.646 +} 1.647 + 1.648 +// Note that this method re-builds the automatic data in the children -- not 1.649 +// in aParentFrame itself (except for those particular operations that the 1.650 +// parent frame may do in its TransmitAutomaticData()). 1.651 +/* static */ void 1.652 +nsMathMLContainerFrame::RebuildAutomaticDataForChildren(nsIFrame* aParentFrame) 1.653 +{ 1.654 + // 1. As we descend the tree, make each child frame inherit data from 1.655 + // the parent 1.656 + // 2. As we ascend the tree, transmit any specific change that we want 1.657 + // down the subtrees 1.658 + nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild(); 1.659 + while (childFrame) { 1.660 + nsIMathMLFrame* childMathMLFrame = do_QueryFrame(childFrame); 1.661 + if (childMathMLFrame) { 1.662 + childMathMLFrame->InheritAutomaticData(aParentFrame); 1.663 + } 1.664 + RebuildAutomaticDataForChildren(childFrame); 1.665 + childFrame = childFrame->GetNextSibling(); 1.666 + } 1.667 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(aParentFrame); 1.668 + if (mathMLFrame) { 1.669 + mathMLFrame->TransmitAutomaticData(); 1.670 + } 1.671 +} 1.672 + 1.673 +/* static */ nsresult 1.674 +nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame) 1.675 +{ 1.676 + if (!aParentFrame) 1.677 + return NS_OK; 1.678 + 1.679 + // walk-up to the first frame that is a MathML frame, stop if we reach <math> 1.680 + nsIFrame* frame = aParentFrame; 1.681 + while (1) { 1.682 + nsIFrame* parent = frame->GetParent(); 1.683 + if (!parent || !parent->GetContent()) 1.684 + break; 1.685 + 1.686 + // stop if it is a MathML frame 1.687 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(frame); 1.688 + if (mathMLFrame) 1.689 + break; 1.690 + 1.691 + // stop if we reach the root <math> tag 1.692 + nsIContent* content = frame->GetContent(); 1.693 + NS_ASSERTION(content, "dangling frame without a content node"); 1.694 + if (!content) 1.695 + break; 1.696 + if (content->GetNameSpaceID() == kNameSpaceID_MathML && 1.697 + content->Tag() == nsGkAtoms::math) 1.698 + break; 1.699 + 1.700 + frame = parent; 1.701 + } 1.702 + 1.703 + // re-sync the presentation data and embellishment data of our children 1.704 + RebuildAutomaticDataForChildren(frame); 1.705 + 1.706 + // Ask our parent frame to reflow us 1.707 + nsIFrame* parent = frame->GetParent(); 1.708 + NS_ASSERTION(parent, "No parent to pass the reflow request up to"); 1.709 + if (!parent) 1.710 + return NS_OK; 1.711 + 1.712 + frame->PresContext()->PresShell()-> 1.713 + FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); 1.714 + 1.715 + return NS_OK; 1.716 +} 1.717 + 1.718 +// There are precise rules governing children of a MathML frame, 1.719 +// and properties such as the scriptlevel depends on those rules. 1.720 +// Hence for things to work, callers must use Append/Insert/etc wisely. 1.721 + 1.722 +nsresult 1.723 +nsMathMLContainerFrame::ChildListChanged(int32_t aModType) 1.724 +{ 1.725 + // If this is an embellished frame we need to rebuild the 1.726 + // embellished hierarchy by walking-up to the parent of the 1.727 + // outermost embellished container. 1.728 + nsIFrame* frame = this; 1.729 + if (mEmbellishData.coreFrame) { 1.730 + nsIFrame* parent = mParent; 1.731 + nsEmbellishData embellishData; 1.732 + for ( ; parent; frame = parent, parent = parent->GetParent()) { 1.733 + GetEmbellishDataFrom(parent, embellishData); 1.734 + if (embellishData.coreFrame != mEmbellishData.coreFrame) 1.735 + break; 1.736 + } 1.737 + } 1.738 + return ReLayoutChildren(frame); 1.739 +} 1.740 + 1.741 +nsresult 1.742 +nsMathMLContainerFrame::AppendFrames(ChildListID aListID, 1.743 + nsFrameList& aFrameList) 1.744 +{ 1.745 + if (aListID != kPrincipalList) { 1.746 + return NS_ERROR_INVALID_ARG; 1.747 + } 1.748 + mFrames.AppendFrames(this, aFrameList); 1.749 + return ChildListChanged(nsIDOMMutationEvent::ADDITION); 1.750 +} 1.751 + 1.752 +nsresult 1.753 +nsMathMLContainerFrame::InsertFrames(ChildListID aListID, 1.754 + nsIFrame* aPrevFrame, 1.755 + nsFrameList& aFrameList) 1.756 +{ 1.757 + if (aListID != kPrincipalList) { 1.758 + return NS_ERROR_INVALID_ARG; 1.759 + } 1.760 + // Insert frames after aPrevFrame 1.761 + mFrames.InsertFrames(this, aPrevFrame, aFrameList); 1.762 + return ChildListChanged(nsIDOMMutationEvent::ADDITION); 1.763 +} 1.764 + 1.765 +nsresult 1.766 +nsMathMLContainerFrame::RemoveFrame(ChildListID aListID, 1.767 + nsIFrame* aOldFrame) 1.768 +{ 1.769 + if (aListID != kPrincipalList) { 1.770 + return NS_ERROR_INVALID_ARG; 1.771 + } 1.772 + // remove the child frame 1.773 + mFrames.DestroyFrame(aOldFrame); 1.774 + return ChildListChanged(nsIDOMMutationEvent::REMOVAL); 1.775 +} 1.776 + 1.777 +nsresult 1.778 +nsMathMLContainerFrame::AttributeChanged(int32_t aNameSpaceID, 1.779 + nsIAtom* aAttribute, 1.780 + int32_t aModType) 1.781 +{ 1.782 + // XXX Since they are numerous MathML attributes that affect layout, and 1.783 + // we can't check all of them here, play safe by requesting a reflow. 1.784 + // XXXldb This should only do work for attributes that cause changes! 1.785 + PresContext()->PresShell()-> 1.786 + FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); 1.787 + 1.788 + return NS_OK; 1.789 +} 1.790 + 1.791 +void 1.792 +nsMathMLContainerFrame::GatherAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) 1.793 +{ 1.794 + // nsIFrame::FinishAndStoreOverflow likes the overflow area to include the 1.795 + // frame rectangle. 1.796 + aMetrics->SetOverflowAreasToDesiredBounds(); 1.797 + 1.798 + // All non-child-frame content such as nsMathMLChars (and most child-frame 1.799 + // content) is included in mBoundingMetrics. 1.800 + nsRect boundingBox(mBoundingMetrics.leftBearing, 1.801 + aMetrics->TopAscent() - mBoundingMetrics.ascent, 1.802 + mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing, 1.803 + mBoundingMetrics.ascent + mBoundingMetrics.descent); 1.804 + 1.805 + // REVIEW: Maybe this should contribute only to visual overflow 1.806 + // and not scrollable? 1.807 + aMetrics->mOverflowAreas.UnionAllWith(boundingBox); 1.808 + 1.809 + // mBoundingMetrics does not necessarily include content of <mpadded> 1.810 + // elements whose mBoundingMetrics may not be representative of the true 1.811 + // bounds, and doesn't include the CSS2 outline rectangles of children, so 1.812 + // make such to include child overflow areas. 1.813 + nsIFrame* childFrame = mFrames.FirstChild(); 1.814 + while (childFrame) { 1.815 + ConsiderChildOverflow(aMetrics->mOverflowAreas, childFrame); 1.816 + childFrame = childFrame->GetNextSibling(); 1.817 + } 1.818 + 1.819 + FinishAndStoreOverflow(aMetrics); 1.820 +} 1.821 + 1.822 +bool 1.823 +nsMathMLContainerFrame::UpdateOverflow() 1.824 +{ 1.825 + // Our overflow areas may have changed, so reflow the frame. 1.826 + PresContext()->PresShell()->FrameNeedsReflow( 1.827 + this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); 1.828 + 1.829 + // As we're reflowing, there's no need to propagate this change. 1.830 + return false; 1.831 +} 1.832 + 1.833 +nsresult 1.834 +nsMathMLContainerFrame::ReflowChild(nsIFrame* aChildFrame, 1.835 + nsPresContext* aPresContext, 1.836 + nsHTMLReflowMetrics& aDesiredSize, 1.837 + const nsHTMLReflowState& aReflowState, 1.838 + nsReflowStatus& aStatus) 1.839 +{ 1.840 + // Having foreign/hybrid children, e.g., from html markups, is not defined by 1.841 + // the MathML spec. But it can happen in practice, e.g., <html:img> allows us 1.842 + // to do some cool demos... or we may have a child that is an nsInlineFrame 1.843 + // from a generated content such as :before { content: open-quote } or 1.844 + // :after { content: close-quote }. Unfortunately, the other frames out-there 1.845 + // may expect their own invariants that are not met when we mix things. 1.846 + // Hence we do not claim their support, but we will nevertheless attempt to keep 1.847 + // them in the flow, if we can get their desired size. We observed that most 1.848 + // frames may be reflowed generically, but nsInlineFrames need extra care. 1.849 + 1.850 +#ifdef DEBUG 1.851 + nsInlineFrame* inlineFrame = do_QueryFrame(aChildFrame); 1.852 + NS_ASSERTION(!inlineFrame, "Inline frames should be wrapped in blocks"); 1.853 +#endif 1.854 + 1.855 + nsresult rv = nsContainerFrame:: 1.856 + ReflowChild(aChildFrame, aPresContext, aDesiredSize, aReflowState, 1.857 + 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); 1.858 + 1.859 + if (NS_FAILED(rv)) 1.860 + return rv; 1.861 + 1.862 + if (aDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) { 1.863 + // This will be suitable for inline frames, which are wrapped in a block. 1.864 + nscoord ascent; 1.865 + if (!nsLayoutUtils::GetLastLineBaseline(aChildFrame, 1.866 + &ascent)) { 1.867 + // We don't expect any other block children so just place the frame on 1.868 + // the baseline instead of going through DidReflow() and 1.869 + // GetBaseline(). This is what nsFrame::GetBaseline() will do anyway. 1.870 + aDesiredSize.SetTopAscent(aDesiredSize.Height()); 1.871 + } else { 1.872 + aDesiredSize.SetTopAscent(ascent); 1.873 + } 1.874 + } 1.875 + if (IsForeignChild(aChildFrame)) { 1.876 + // use ComputeTightBounds API as aDesiredSize.mBoundingMetrics is not set. 1.877 + nsRect r = aChildFrame->ComputeTightBounds(aReflowState.rendContext->ThebesContext()); 1.878 + aDesiredSize.mBoundingMetrics.leftBearing = r.x; 1.879 + aDesiredSize.mBoundingMetrics.rightBearing = r.XMost(); 1.880 + aDesiredSize.mBoundingMetrics.ascent = aDesiredSize.TopAscent() - r.y; 1.881 + aDesiredSize.mBoundingMetrics.descent = r.YMost() - aDesiredSize.TopAscent(); 1.882 + aDesiredSize.mBoundingMetrics.width = aDesiredSize.Width(); 1.883 + } 1.884 + return rv; 1.885 +} 1.886 + 1.887 +nsresult 1.888 +nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext, 1.889 + nsHTMLReflowMetrics& aDesiredSize, 1.890 + const nsHTMLReflowState& aReflowState, 1.891 + nsReflowStatus& aStatus) 1.892 +{ 1.893 + aDesiredSize.Width() = aDesiredSize.Height() = 0; 1.894 + aDesiredSize.SetTopAscent(0); 1.895 + aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); 1.896 + 1.897 + ///////////// 1.898 + // Reflow children 1.899 + // Asking each child to cache its bounding metrics 1.900 + 1.901 + nsReflowStatus childStatus; 1.902 + nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); 1.903 + nsIFrame* childFrame = mFrames.FirstChild(); 1.904 + while (childFrame) { 1.905 + nsHTMLReflowMetrics childDesiredSize(aReflowState, // ??? 1.906 + aDesiredSize.mFlags); 1.907 + nsHTMLReflowState childReflowState(aPresContext, aReflowState, 1.908 + childFrame, availSize); 1.909 + nsresult rv = ReflowChild(childFrame, aPresContext, childDesiredSize, 1.910 + childReflowState, childStatus); 1.911 + //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); 1.912 + if (NS_FAILED(rv)) { 1.913 + // Call DidReflow() for the child frames we successfully did reflow. 1.914 + DidReflowChildren(mFrames.FirstChild(), childFrame); 1.915 + return rv; 1.916 + } 1.917 + 1.918 + SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, 1.919 + childDesiredSize.mBoundingMetrics); 1.920 + childFrame = childFrame->GetNextSibling(); 1.921 + } 1.922 + 1.923 + ///////////// 1.924 + // If we are a container which is entitled to stretch its children, then we 1.925 + // ask our stretchy children to stretch themselves 1.926 + 1.927 + // The stretching of siblings of an embellished child is _deferred_ until 1.928 + // after finishing the stretching of the embellished child - bug 117652 1.929 + 1.930 + if (!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) && 1.931 + (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || 1.932 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags))) { 1.933 + 1.934 + // get the stretchy direction 1.935 + nsStretchDirection stretchDir = 1.936 + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) 1.937 + ? NS_STRETCH_DIRECTION_VERTICAL 1.938 + : NS_STRETCH_DIRECTION_HORIZONTAL; 1.939 + 1.940 + // what size should we use to stretch our stretchy children 1.941 + // We don't use STRETCH_CONSIDER_ACTUAL_SIZE -- because our size is not known yet 1.942 + // We don't use STRETCH_CONSIDER_EMBELLISHMENTS -- because we don't want to 1.943 + // include them in the caculations of the size of stretchy elements 1.944 + nsBoundingMetrics containerSize; 1.945 + GetPreferredStretchSize(*aReflowState.rendContext, 0, stretchDir, 1.946 + containerSize); 1.947 + 1.948 + // fire the stretch on each child 1.949 + childFrame = mFrames.FirstChild(); 1.950 + while (childFrame) { 1.951 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame); 1.952 + if (mathMLFrame) { 1.953 + // retrieve the metrics that was stored at the previous pass 1.954 + nsHTMLReflowMetrics childDesiredSize(aReflowState); 1.955 + GetReflowAndBoundingMetricsFor(childFrame, 1.956 + childDesiredSize, childDesiredSize.mBoundingMetrics); 1.957 + 1.958 + mathMLFrame->Stretch(*aReflowState.rendContext, stretchDir, 1.959 + containerSize, childDesiredSize); 1.960 + // store the updated metrics 1.961 + SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, 1.962 + childDesiredSize.mBoundingMetrics); 1.963 + } 1.964 + childFrame = childFrame->GetNextSibling(); 1.965 + } 1.966 + } 1.967 + 1.968 + ///////////// 1.969 + // Place children now by re-adjusting the origins to align the baselines 1.970 + FinalizeReflow(*aReflowState.rendContext, aDesiredSize); 1.971 + 1.972 + aStatus = NS_FRAME_COMPLETE; 1.973 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.974 + return NS_OK; 1.975 +} 1.976 + 1.977 +static nscoord AddInterFrameSpacingToSize(nsHTMLReflowMetrics& aDesiredSize, 1.978 + nsMathMLContainerFrame* aFrame); 1.979 + 1.980 +/* virtual */ nscoord 1.981 +nsMathMLContainerFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.982 +{ 1.983 + nscoord result; 1.984 + DISPLAY_MIN_WIDTH(this, result); 1.985 + nsHTMLReflowMetrics desiredSize(GetWritingMode()); 1.986 + GetIntrinsicWidthMetrics(aRenderingContext, desiredSize); 1.987 + 1.988 + // Include the additional width added by FixInterFrameSpacing to ensure 1.989 + // consistent width calculations. 1.990 + AddInterFrameSpacingToSize(desiredSize, this); 1.991 + result = desiredSize.Width(); 1.992 + return result; 1.993 +} 1.994 + 1.995 +/* virtual */ nscoord 1.996 +nsMathMLContainerFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.997 +{ 1.998 + nscoord result; 1.999 + DISPLAY_PREF_WIDTH(this, result); 1.1000 + nsHTMLReflowMetrics desiredSize(GetWritingMode()); 1.1001 + GetIntrinsicWidthMetrics(aRenderingContext, desiredSize); 1.1002 + 1.1003 + // Include the additional width added by FixInterFrameSpacing to ensure 1.1004 + // consistent width calculations. 1.1005 + AddInterFrameSpacingToSize(desiredSize, this); 1.1006 + result = desiredSize.Width(); 1.1007 + return result; 1.1008 +} 1.1009 + 1.1010 +/* virtual */ void 1.1011 +nsMathMLContainerFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize) 1.1012 +{ 1.1013 + // Get child widths 1.1014 + nsIFrame* childFrame = mFrames.FirstChild(); 1.1015 + while (childFrame) { 1.1016 + nsHTMLReflowMetrics childDesiredSize(GetWritingMode()); // ??? 1.1017 + 1.1018 + nsMathMLContainerFrame* containerFrame = do_QueryFrame(childFrame); 1.1019 + if (containerFrame) { 1.1020 + containerFrame->GetIntrinsicWidthMetrics(aRenderingContext, 1.1021 + childDesiredSize); 1.1022 + } else { 1.1023 + // XXX This includes margin while Reflow currently doesn't consider 1.1024 + // margin, so we may end up with too much space, but, with stretchy 1.1025 + // characters, this is an approximation anyway. 1.1026 + nscoord width = 1.1027 + nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame, 1.1028 + nsLayoutUtils::PREF_WIDTH); 1.1029 + 1.1030 + childDesiredSize.Width() = width; 1.1031 + childDesiredSize.mBoundingMetrics.width = width; 1.1032 + childDesiredSize.mBoundingMetrics.leftBearing = 0; 1.1033 + childDesiredSize.mBoundingMetrics.rightBearing = width; 1.1034 + 1.1035 + nscoord x, xMost; 1.1036 + if (NS_SUCCEEDED(childFrame->GetPrefWidthTightBounds(aRenderingContext, 1.1037 + &x, &xMost))) { 1.1038 + childDesiredSize.mBoundingMetrics.leftBearing = x; 1.1039 + childDesiredSize.mBoundingMetrics.rightBearing = xMost; 1.1040 + } 1.1041 + } 1.1042 + 1.1043 + SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, 1.1044 + childDesiredSize.mBoundingMetrics); 1.1045 + 1.1046 + childFrame = childFrame->GetNextSibling(); 1.1047 + } 1.1048 + 1.1049 + // Measure 1.1050 + nsresult rv = MeasureForWidth(*aRenderingContext, aDesiredSize); 1.1051 + if (NS_FAILED(rv)) { 1.1052 + ReflowError(*aRenderingContext, aDesiredSize); 1.1053 + } 1.1054 + 1.1055 + ClearSavedChildMetrics(); 1.1056 +} 1.1057 + 1.1058 +/* virtual */ nsresult 1.1059 +nsMathMLContainerFrame::MeasureForWidth(nsRenderingContext& aRenderingContext, 1.1060 + nsHTMLReflowMetrics& aDesiredSize) 1.1061 +{ 1.1062 + return Place(aRenderingContext, false, aDesiredSize); 1.1063 +} 1.1064 + 1.1065 + 1.1066 +// see spacing table in Chapter 18, TeXBook (p.170) 1.1067 +// Our table isn't quite identical to TeX because operators have 1.1068 +// built-in values for lspace & rspace in the Operator Dictionary. 1.1069 +static int32_t kInterFrameSpacingTable[eMathMLFrameType_COUNT][eMathMLFrameType_COUNT] = 1.1070 +{ 1.1071 + // in units of muspace. 1.1072 + // upper half of the byte is set if the 1.1073 + // spacing is not to be used for scriptlevel > 0 1.1074 + 1.1075 + /* Ord OpOrd OpInv OpUsr Inner Italic Upright */ 1.1076 + /*Ord */ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00}, 1.1077 + /*OpOrd*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1.1078 + /*OpInv*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1.1079 + /*OpUsr*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01}, 1.1080 + /*Inner*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01}, 1.1081 + /*Italic*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01}, 1.1082 + /*Upright*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00} 1.1083 +}; 1.1084 + 1.1085 +#define GET_INTERSPACE(scriptlevel_, frametype1_, frametype2_, space_) \ 1.1086 + /* no space if there is a frame that we know nothing about */ \ 1.1087 + if (frametype1_ == eMathMLFrameType_UNKNOWN || \ 1.1088 + frametype2_ == eMathMLFrameType_UNKNOWN) \ 1.1089 + space_ = 0; \ 1.1090 + else { \ 1.1091 + space_ = kInterFrameSpacingTable[frametype1_][frametype2_]; \ 1.1092 + space_ = (scriptlevel_ > 0 && (space_ & 0xF0)) \ 1.1093 + ? 0 /* spacing is disabled */ \ 1.1094 + : space_ & 0x0F; \ 1.1095 + } \ 1.1096 + 1.1097 +// This function computes the inter-space between two frames. However, 1.1098 +// since invisible operators need special treatment, the inter-space may 1.1099 +// be delayed when an invisible operator is encountered. In this case, 1.1100 +// the function will carry the inter-space forward until it is determined 1.1101 +// that it can be applied properly (i.e., until we encounter a visible 1.1102 +// frame where to decide whether to accept or reject the inter-space). 1.1103 +// aFromFrameType: remembers the frame when the carry-forward initiated. 1.1104 +// aCarrySpace: keeps track of the inter-space that is delayed. 1.1105 +// @returns: current inter-space (which is 0 when the true inter-space is 1.1106 +// delayed -- and thus has no effect since the frame is invisible anyway). 1.1107 +static nscoord 1.1108 +GetInterFrameSpacing(int32_t aScriptLevel, 1.1109 + eMathMLFrameType aFirstFrameType, 1.1110 + eMathMLFrameType aSecondFrameType, 1.1111 + eMathMLFrameType* aFromFrameType, // IN/OUT 1.1112 + int32_t* aCarrySpace) // IN/OUT 1.1113 +{ 1.1114 + eMathMLFrameType firstType = aFirstFrameType; 1.1115 + eMathMLFrameType secondType = aSecondFrameType; 1.1116 + 1.1117 + int32_t space; 1.1118 + GET_INTERSPACE(aScriptLevel, firstType, secondType, space); 1.1119 + 1.1120 + // feedback control to avoid the inter-space to be added when not necessary 1.1121 + if (secondType == eMathMLFrameType_OperatorInvisible) { 1.1122 + // see if we should start to carry the space forward until we 1.1123 + // encounter a visible frame 1.1124 + if (*aFromFrameType == eMathMLFrameType_UNKNOWN) { 1.1125 + *aFromFrameType = firstType; 1.1126 + *aCarrySpace = space; 1.1127 + } 1.1128 + // keep carrying *aCarrySpace forward, while returning 0 for this stage 1.1129 + space = 0; 1.1130 + } 1.1131 + else if (*aFromFrameType != eMathMLFrameType_UNKNOWN) { 1.1132 + // no carry-forward anymore, get the real inter-space between 1.1133 + // the two frames of interest 1.1134 + 1.1135 + firstType = *aFromFrameType; 1.1136 + 1.1137 + // But... the invisible operator that we encountered earlier could 1.1138 + // be sitting between italic and upright identifiers, e.g., 1.1139 + // 1.1140 + // 1. <mi>sin</mi> <mo>⁡</mo> <mi>x</mi> 1.1141 + // 2. <mi>x</mi> <mo>&InvisibileTime;</mo> <mi>sin</mi> 1.1142 + // 1.1143 + // the trick to get the inter-space in either situation 1.1144 + // is to promote "<mi>sin</mi><mo>⁡</mo>" and 1.1145 + // "<mo>&InvisibileTime;</mo><mi>sin</mi>" to user-defined operators... 1.1146 + if (firstType == eMathMLFrameType_UprightIdentifier) { 1.1147 + firstType = eMathMLFrameType_OperatorUserDefined; 1.1148 + } 1.1149 + else if (secondType == eMathMLFrameType_UprightIdentifier) { 1.1150 + secondType = eMathMLFrameType_OperatorUserDefined; 1.1151 + } 1.1152 + 1.1153 + GET_INTERSPACE(aScriptLevel, firstType, secondType, space); 1.1154 + 1.1155 + // Now, we have two values: the computed space and the space that 1.1156 + // has been carried forward until now. Which value do we pick? 1.1157 + // If the second type is an operator (e.g., fence), it already has 1.1158 + // built-in lspace & rspace, so we let them win. Otherwise we pick 1.1159 + // the max between the two values that we have. 1.1160 + if (secondType != eMathMLFrameType_OperatorOrdinary && 1.1161 + space < *aCarrySpace) 1.1162 + space = *aCarrySpace; 1.1163 + 1.1164 + // reset everything now that the carry-forward is done 1.1165 + *aFromFrameType = eMathMLFrameType_UNKNOWN; 1.1166 + *aCarrySpace = 0; 1.1167 + } 1.1168 + 1.1169 + return space; 1.1170 +} 1.1171 + 1.1172 +static nscoord GetThinSpace(const nsStyleFont* aStyleFont) 1.1173 +{ 1.1174 + return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18)); 1.1175 +} 1.1176 + 1.1177 +class nsMathMLContainerFrame::RowChildFrameIterator { 1.1178 +public: 1.1179 + explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) : 1.1180 + mParentFrame(aParentFrame), 1.1181 + mSize(aParentFrame->GetWritingMode()), // ??? 1.1182 + mX(0), 1.1183 + mCarrySpace(0), 1.1184 + mFromFrameType(eMathMLFrameType_UNKNOWN), 1.1185 + mRTL(aParentFrame->StyleVisibility()->mDirection) 1.1186 + { 1.1187 + if (!mRTL) { 1.1188 + mChildFrame = aParentFrame->mFrames.FirstChild(); 1.1189 + } else { 1.1190 + mChildFrame = aParentFrame->mFrames.LastChild(); 1.1191 + } 1.1192 + 1.1193 + if (!mChildFrame) 1.1194 + return; 1.1195 + 1.1196 + InitMetricsForChild(); 1.1197 + } 1.1198 + 1.1199 + RowChildFrameIterator& operator++() 1.1200 + { 1.1201 + // add child size + italic correction 1.1202 + mX += mSize.mBoundingMetrics.width + mItalicCorrection; 1.1203 + 1.1204 + if (!mRTL) { 1.1205 + mChildFrame = mChildFrame->GetNextSibling(); 1.1206 + } else { 1.1207 + mChildFrame = mChildFrame->GetPrevSibling(); 1.1208 + } 1.1209 + 1.1210 + if (!mChildFrame) 1.1211 + return *this; 1.1212 + 1.1213 + eMathMLFrameType prevFrameType = mChildFrameType; 1.1214 + InitMetricsForChild(); 1.1215 + 1.1216 + // add inter frame spacing 1.1217 + const nsStyleFont* font = mParentFrame->StyleFont(); 1.1218 + nscoord space = 1.1219 + GetInterFrameSpacing(font->mScriptLevel, 1.1220 + prevFrameType, mChildFrameType, 1.1221 + &mFromFrameType, &mCarrySpace); 1.1222 + mX += space * GetThinSpace(font); 1.1223 + return *this; 1.1224 + } 1.1225 + 1.1226 + nsIFrame* Frame() const { return mChildFrame; } 1.1227 + nscoord X() const { return mX; } 1.1228 + const nsHTMLReflowMetrics& ReflowMetrics() const { return mSize; } 1.1229 + nscoord Ascent() const { return mSize.TopAscent(); } 1.1230 + nscoord Descent() const { return mSize.Height() - mSize.TopAscent(); } 1.1231 + const nsBoundingMetrics& BoundingMetrics() const { 1.1232 + return mSize.mBoundingMetrics; 1.1233 + } 1.1234 + 1.1235 +private: 1.1236 + const nsMathMLContainerFrame* mParentFrame; 1.1237 + nsIFrame* mChildFrame; 1.1238 + nsHTMLReflowMetrics mSize; 1.1239 + nscoord mX; 1.1240 + 1.1241 + nscoord mItalicCorrection; 1.1242 + eMathMLFrameType mChildFrameType; 1.1243 + int32_t mCarrySpace; 1.1244 + eMathMLFrameType mFromFrameType; 1.1245 + 1.1246 + bool mRTL; 1.1247 + 1.1248 + void InitMetricsForChild() 1.1249 + { 1.1250 + GetReflowAndBoundingMetricsFor(mChildFrame, mSize, mSize.mBoundingMetrics, 1.1251 + &mChildFrameType); 1.1252 + nscoord leftCorrection, rightCorrection; 1.1253 + GetItalicCorrection(mSize.mBoundingMetrics, 1.1254 + leftCorrection, rightCorrection); 1.1255 + if (!mChildFrame->GetPrevSibling() && 1.1256 + mParentFrame->GetContent()->Tag() == nsGkAtoms::msqrt_) { 1.1257 + // Remove leading correction in <msqrt> because the sqrt glyph itself is 1.1258 + // there first. 1.1259 + if (!mRTL) { 1.1260 + leftCorrection = 0; 1.1261 + } else { 1.1262 + rightCorrection = 0; 1.1263 + } 1.1264 + } 1.1265 + // add left correction -- this fixes the problem of the italic 'f' 1.1266 + // e.g., <mo>q</mo> <mi>f</mi> <mo>I</mo> 1.1267 + mX += leftCorrection; 1.1268 + mItalicCorrection = rightCorrection; 1.1269 + } 1.1270 +}; 1.1271 + 1.1272 +/* virtual */ nsresult 1.1273 +nsMathMLContainerFrame::Place(nsRenderingContext& aRenderingContext, 1.1274 + bool aPlaceOrigin, 1.1275 + nsHTMLReflowMetrics& aDesiredSize) 1.1276 +{ 1.1277 + // This is needed in case this frame is empty (i.e., no child frames) 1.1278 + mBoundingMetrics = nsBoundingMetrics(); 1.1279 + 1.1280 + RowChildFrameIterator child(this); 1.1281 + nscoord ascent = 0, descent = 0; 1.1282 + while (child.Frame()) { 1.1283 + if (descent < child.Descent()) 1.1284 + descent = child.Descent(); 1.1285 + if (ascent < child.Ascent()) 1.1286 + ascent = child.Ascent(); 1.1287 + // add the child size 1.1288 + mBoundingMetrics.width = child.X(); 1.1289 + mBoundingMetrics += child.BoundingMetrics(); 1.1290 + ++child; 1.1291 + } 1.1292 + // Add the italic correction at the end (including the last child). 1.1293 + // This gives a nice gap between math and non-math frames, and still 1.1294 + // gives the same math inter-spacing in case this frame connects to 1.1295 + // another math frame 1.1296 + mBoundingMetrics.width = child.X(); 1.1297 + 1.1298 + aDesiredSize.Width() = std::max(0, mBoundingMetrics.width); 1.1299 + aDesiredSize.Height() = ascent + descent; 1.1300 + aDesiredSize.SetTopAscent(ascent); 1.1301 + aDesiredSize.mBoundingMetrics = mBoundingMetrics; 1.1302 + 1.1303 + mReference.x = 0; 1.1304 + mReference.y = aDesiredSize.TopAscent(); 1.1305 + 1.1306 + ////////////////// 1.1307 + // Place Children 1.1308 + 1.1309 + if (aPlaceOrigin) { 1.1310 + PositionRowChildFrames(0, aDesiredSize.TopAscent()); 1.1311 + } 1.1312 + 1.1313 + return NS_OK; 1.1314 +} 1.1315 + 1.1316 +void 1.1317 +nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX, 1.1318 + nscoord aBaseline) 1.1319 +{ 1.1320 + RowChildFrameIterator child(this); 1.1321 + while (child.Frame()) { 1.1322 + nscoord dx = aOffsetX + child.X(); 1.1323 + nscoord dy = aBaseline - child.Ascent(); 1.1324 + FinishReflowChild(child.Frame(), PresContext(), child.ReflowMetrics(), 1.1325 + nullptr, dx, dy, 0); 1.1326 + ++child; 1.1327 + } 1.1328 +} 1.1329 + 1.1330 +class ForceReflow : public nsIReflowCallback { 1.1331 +public: 1.1332 + virtual bool ReflowFinished() MOZ_OVERRIDE { 1.1333 + return true; 1.1334 + } 1.1335 + virtual void ReflowCallbackCanceled() MOZ_OVERRIDE {} 1.1336 +}; 1.1337 + 1.1338 +// We only need one of these so we just make it a static global, no need 1.1339 +// to dynamically allocate/destroy it. 1.1340 +static ForceReflow gForceReflow; 1.1341 + 1.1342 +void 1.1343 +nsMathMLContainerFrame::SetIncrementScriptLevel(int32_t aChildIndex, bool aIncrement) 1.1344 +{ 1.1345 + nsIFrame* child = PrincipalChildList().FrameAt(aChildIndex); 1.1346 + if (!child) 1.1347 + return; 1.1348 + nsIContent* content = child->GetContent(); 1.1349 + if (!content->IsMathML()) 1.1350 + return; 1.1351 + nsMathMLElement* element = static_cast<nsMathMLElement*>(content); 1.1352 + 1.1353 + if (element->GetIncrementScriptLevel() == aIncrement) 1.1354 + return; 1.1355 + 1.1356 + // XXXroc this does a ContentStatesChanged, is it safe to call here? If 1.1357 + // not we should do it in a post-reflow callback. 1.1358 + element->SetIncrementScriptLevel(aIncrement, true); 1.1359 + PresContext()->PresShell()->PostReflowCallback(&gForceReflow); 1.1360 +} 1.1361 + 1.1362 +// helpers to fix the inter-spacing when <math> is the only parent 1.1363 +// e.g., it fixes <math> <mi>f</mi> <mo>q</mo> <mi>f</mi> <mo>I</mo> </math> 1.1364 + 1.1365 +static nscoord 1.1366 +GetInterFrameSpacingFor(int32_t aScriptLevel, 1.1367 + nsIFrame* aParentFrame, 1.1368 + nsIFrame* aChildFrame) 1.1369 +{ 1.1370 + nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild(); 1.1371 + if (!childFrame || aChildFrame == childFrame) 1.1372 + return 0; 1.1373 + 1.1374 + int32_t carrySpace = 0; 1.1375 + eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN; 1.1376 + eMathMLFrameType prevFrameType = eMathMLFrameType_UNKNOWN; 1.1377 + eMathMLFrameType childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame); 1.1378 + childFrame = childFrame->GetNextSibling(); 1.1379 + while (childFrame) { 1.1380 + prevFrameType = childFrameType; 1.1381 + childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame); 1.1382 + nscoord space = GetInterFrameSpacing(aScriptLevel, 1.1383 + prevFrameType, childFrameType, &fromFrameType, &carrySpace); 1.1384 + if (aChildFrame == childFrame) { 1.1385 + // get thinspace 1.1386 + nsStyleContext* parentContext = aParentFrame->StyleContext(); 1.1387 + nscoord thinSpace = GetThinSpace(parentContext->StyleFont()); 1.1388 + // we are done 1.1389 + return space * thinSpace; 1.1390 + } 1.1391 + childFrame = childFrame->GetNextSibling(); 1.1392 + } 1.1393 + 1.1394 + NS_NOTREACHED("child not in the childlist of its parent"); 1.1395 + return 0; 1.1396 +} 1.1397 + 1.1398 +static nscoord 1.1399 +AddInterFrameSpacingToSize(nsHTMLReflowMetrics& aDesiredSize, 1.1400 + nsMathMLContainerFrame* aFrame) 1.1401 +{ 1.1402 + nscoord gap = 0; 1.1403 + nsIFrame* parent = aFrame->GetParent(); 1.1404 + nsIContent* parentContent = parent->GetContent(); 1.1405 + if (MOZ_UNLIKELY(!parentContent)) { 1.1406 + return 0; 1.1407 + } 1.1408 + nsIAtom *parentTag = parentContent->Tag(); 1.1409 + if (parentContent->GetNameSpaceID() == kNameSpaceID_MathML && 1.1410 + (parentTag == nsGkAtoms::math || parentTag == nsGkAtoms::mtd_)) { 1.1411 + gap = GetInterFrameSpacingFor(aFrame->StyleFont()->mScriptLevel, 1.1412 + parent, aFrame); 1.1413 + // add our own italic correction 1.1414 + nscoord leftCorrection = 0, italicCorrection = 0; 1.1415 + aFrame->GetItalicCorrection(aDesiredSize.mBoundingMetrics, 1.1416 + leftCorrection, italicCorrection); 1.1417 + gap += leftCorrection; 1.1418 + if (gap) { 1.1419 + aDesiredSize.mBoundingMetrics.leftBearing += gap; 1.1420 + aDesiredSize.mBoundingMetrics.rightBearing += gap; 1.1421 + aDesiredSize.mBoundingMetrics.width += gap; 1.1422 + aDesiredSize.Width() += gap; 1.1423 + } 1.1424 + aDesiredSize.mBoundingMetrics.width += italicCorrection; 1.1425 + aDesiredSize.Width() += italicCorrection; 1.1426 + } 1.1427 + return gap; 1.1428 +} 1.1429 + 1.1430 +nscoord 1.1431 +nsMathMLContainerFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize) 1.1432 +{ 1.1433 + nscoord gap = 0; 1.1434 + gap = AddInterFrameSpacingToSize(aDesiredSize, this); 1.1435 + if (gap) { 1.1436 + // Shift our children to account for the correction 1.1437 + nsIFrame* childFrame = mFrames.FirstChild(); 1.1438 + while (childFrame) { 1.1439 + childFrame->SetPosition(childFrame->GetPosition() + nsPoint(gap, 0)); 1.1440 + childFrame = childFrame->GetNextSibling(); 1.1441 + } 1.1442 + } 1.1443 + return gap; 1.1444 +} 1.1445 + 1.1446 +/* static */ void 1.1447 +nsMathMLContainerFrame::DidReflowChildren(nsIFrame* aFirst, nsIFrame* aStop) 1.1448 + 1.1449 +{ 1.1450 + if (MOZ_UNLIKELY(!aFirst)) 1.1451 + return; 1.1452 + 1.1453 + for (nsIFrame* frame = aFirst; 1.1454 + frame != aStop; 1.1455 + frame = frame->GetNextSibling()) { 1.1456 + NS_ASSERTION(frame, "aStop isn't a sibling"); 1.1457 + if (frame->GetStateBits() & NS_FRAME_IN_REFLOW) { 1.1458 + // finish off principal descendants, too 1.1459 + nsIFrame* grandchild = frame->GetFirstPrincipalChild(); 1.1460 + if (grandchild) 1.1461 + DidReflowChildren(grandchild, nullptr); 1.1462 + 1.1463 + frame->DidReflow(frame->PresContext(), nullptr, 1.1464 + nsDidReflowStatus::FINISHED); 1.1465 + } 1.1466 + } 1.1467 +} 1.1468 + 1.1469 +// helper used by mstyle, mphantom, mpadded and mrow in their implementations 1.1470 +// of TransmitAutomaticData(). 1.1471 +nsresult 1.1472 +nsMathMLContainerFrame::TransmitAutomaticDataForMrowLikeElement() 1.1473 +{ 1.1474 + // 1.1475 + // One loop to check both conditions below: 1.1476 + // 1.1477 + // 1) whether all the children of the mrow-like element are space-like. 1.1478 + // 1.1479 + // The REC defines the following elements to be "space-like": 1.1480 + // * an mstyle, mphantom, or mpadded element, all of whose direct 1.1481 + // sub-expressions are space-like; 1.1482 + // * an mrow all of whose direct sub-expressions are space-like. 1.1483 + // 1.1484 + // 2) whether all but one child of the mrow-like element are space-like and 1.1485 + // this non-space-like child is an embellished operator. 1.1486 + // 1.1487 + // The REC defines the following elements to be embellished operators: 1.1488 + // * one of the elements mstyle, mphantom, or mpadded, such that an mrow 1.1489 + // containing the same arguments would be an embellished operator; 1.1490 + // * an mrow whose arguments consist (in any order) of one embellished 1.1491 + // operator and zero or more space-like elements. 1.1492 + // 1.1493 + nsIFrame *childFrame, *baseFrame; 1.1494 + bool embellishedOpFound = false; 1.1495 + nsEmbellishData embellishData; 1.1496 + 1.1497 + for (childFrame = GetFirstPrincipalChild(); 1.1498 + childFrame; 1.1499 + childFrame = childFrame->GetNextSibling()) { 1.1500 + nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame); 1.1501 + if (!mathMLFrame) break; 1.1502 + if (!mathMLFrame->IsSpaceLike()) { 1.1503 + if (embellishedOpFound) break; 1.1504 + baseFrame = childFrame; 1.1505 + GetEmbellishDataFrom(baseFrame, embellishData); 1.1506 + if (!NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)) break; 1.1507 + embellishedOpFound = true; 1.1508 + } 1.1509 + } 1.1510 + 1.1511 + if (!childFrame) { 1.1512 + // we successfully went to the end of the loop. This means that one of 1.1513 + // condition 1) or 2) holds. 1.1514 + if (!embellishedOpFound) { 1.1515 + // the mrow-like element is space-like. 1.1516 + mPresentationData.flags |= NS_MATHML_SPACE_LIKE; 1.1517 + } else { 1.1518 + // the mrow-like element is an embellished operator. 1.1519 + // let the state of the embellished operator found bubble to us. 1.1520 + mPresentationData.baseFrame = baseFrame; 1.1521 + mEmbellishData = embellishData; 1.1522 + } 1.1523 + } 1.1524 + 1.1525 + if (childFrame || !embellishedOpFound) { 1.1526 + // The element is not embellished operator 1.1527 + mPresentationData.baseFrame = nullptr; 1.1528 + mEmbellishData.flags = 0; 1.1529 + mEmbellishData.coreFrame = nullptr; 1.1530 + mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; 1.1531 + mEmbellishData.leadingSpace = 0; 1.1532 + mEmbellishData.trailingSpace = 0; 1.1533 + } 1.1534 + 1.1535 + if (childFrame || embellishedOpFound) { 1.1536 + // The element is not space-like 1.1537 + mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE; 1.1538 + } 1.1539 + 1.1540 + return NS_OK; 1.1541 +} 1.1542 + 1.1543 +/*static*/ void 1.1544 +nsMathMLContainerFrame::PropagateFrameFlagFor(nsIFrame* aFrame, 1.1545 + nsFrameState aFlags) 1.1546 +{ 1.1547 + if (!aFrame || !aFlags) 1.1548 + return; 1.1549 + 1.1550 + aFrame->AddStateBits(aFlags); 1.1551 + nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); 1.1552 + while (childFrame) { 1.1553 + PropagateFrameFlagFor(childFrame, aFlags); 1.1554 + childFrame = childFrame->GetNextSibling(); 1.1555 + } 1.1556 +} 1.1557 + 1.1558 +nsresult 1.1559 +nsMathMLContainerFrame::ReportErrorToConsole(const char* errorMsgId, 1.1560 + const char16_t** aParams, 1.1561 + uint32_t aParamCount) 1.1562 +{ 1.1563 + return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, 1.1564 + NS_LITERAL_CSTRING("MathML"), mContent->OwnerDoc(), 1.1565 + nsContentUtils::eMATHML_PROPERTIES, 1.1566 + errorMsgId, aParams, aParamCount); 1.1567 +} 1.1568 + 1.1569 +nsresult 1.1570 +nsMathMLContainerFrame::ReportParseError(const char16_t* aAttribute, 1.1571 + const char16_t* aValue) 1.1572 +{ 1.1573 + const char16_t* argv[] = 1.1574 + { aValue, aAttribute, mContent->Tag()->GetUTF16String() }; 1.1575 + return ReportErrorToConsole("AttributeParsingError", argv, 3); 1.1576 +} 1.1577 + 1.1578 +nsresult 1.1579 +nsMathMLContainerFrame::ReportChildCountError() 1.1580 +{ 1.1581 + const char16_t* arg = mContent->Tag()->GetUTF16String(); 1.1582 + return ReportErrorToConsole("ChildCountIncorrect", &arg, 1); 1.1583 +} 1.1584 + 1.1585 +nsresult 1.1586 +nsMathMLContainerFrame::ReportInvalidChildError(nsIAtom* aChildTag) 1.1587 +{ 1.1588 + const char16_t* argv[] = 1.1589 + { aChildTag->GetUTF16String(), mContent->Tag()->GetUTF16String() }; 1.1590 + return ReportErrorToConsole("InvalidChild", argv, 2); 1.1591 +} 1.1592 + 1.1593 +//========================== 1.1594 + 1.1595 +nsIFrame* 1.1596 +NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, 1.1597 + nsFrameState aFlags) 1.1598 +{ 1.1599 + nsMathMLmathBlockFrame* it = new (aPresShell) nsMathMLmathBlockFrame(aContext); 1.1600 + it->SetFlags(aFlags); 1.1601 + return it; 1.1602 +} 1.1603 + 1.1604 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathBlockFrame) 1.1605 + 1.1606 +NS_QUERYFRAME_HEAD(nsMathMLmathBlockFrame) 1.1607 + NS_QUERYFRAME_ENTRY(nsMathMLmathBlockFrame) 1.1608 +NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame) 1.1609 + 1.1610 +nsIFrame* 1.1611 +NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.1612 +{ 1.1613 + return new (aPresShell) nsMathMLmathInlineFrame(aContext); 1.1614 +} 1.1615 + 1.1616 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathInlineFrame) 1.1617 + 1.1618 +NS_QUERYFRAME_HEAD(nsMathMLmathInlineFrame) 1.1619 + NS_QUERYFRAME_ENTRY(nsIMathMLFrame) 1.1620 +NS_QUERYFRAME_TAIL_INHERITING(nsInlineFrame)