layout/mathml/nsMathMLmfencedFrame.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6
michael@0 7 #include "nsMathMLmfencedFrame.h"
michael@0 8 #include "nsRenderingContext.h"
michael@0 9 #include "nsMathMLChar.h"
michael@0 10 #include <algorithm>
michael@0 11
michael@0 12 //
michael@0 13 // <mfenced> -- surround content with a pair of fences
michael@0 14 //
michael@0 15
michael@0 16 nsIFrame*
michael@0 17 NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 18 {
michael@0 19 return new (aPresShell) nsMathMLmfencedFrame(aContext);
michael@0 20 }
michael@0 21
michael@0 22 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfencedFrame)
michael@0 23
michael@0 24 nsMathMLmfencedFrame::~nsMathMLmfencedFrame()
michael@0 25 {
michael@0 26 RemoveFencesAndSeparators();
michael@0 27 }
michael@0 28
michael@0 29 NS_IMETHODIMP
michael@0 30 nsMathMLmfencedFrame::InheritAutomaticData(nsIFrame* aParent)
michael@0 31 {
michael@0 32 // let the base class get the default from our parent
michael@0 33 nsMathMLContainerFrame::InheritAutomaticData(aParent);
michael@0 34
michael@0 35 mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
michael@0 36
michael@0 37 RemoveFencesAndSeparators();
michael@0 38 CreateFencesAndSeparators(PresContext());
michael@0 39
michael@0 40 return NS_OK;
michael@0 41 }
michael@0 42
michael@0 43 nsresult
michael@0 44 nsMathMLmfencedFrame::SetInitialChildList(ChildListID aListID,
michael@0 45 nsFrameList& aChildList)
michael@0 46 {
michael@0 47 // First, let the base class do its work
michael@0 48 nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
michael@0 49 if (NS_FAILED(rv)) return rv;
michael@0 50
michael@0 51 // InheritAutomaticData will not get called if our parent is not a mathml
michael@0 52 // frame, so initialize NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for
michael@0 53 // GetPreferredStretchSize() from Reflow().
michael@0 54 mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
michael@0 55 // No need to track the style contexts given to our MathML chars.
michael@0 56 // The Style System will use Get/SetAdditionalStyleContext() to keep them
michael@0 57 // up-to-date if dynamic changes arise.
michael@0 58 CreateFencesAndSeparators(PresContext());
michael@0 59 return NS_OK;
michael@0 60 }
michael@0 61
michael@0 62 nsresult
michael@0 63 nsMathMLmfencedFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 64 nsIAtom* aAttribute,
michael@0 65 int32_t aModType)
michael@0 66 {
michael@0 67 RemoveFencesAndSeparators();
michael@0 68 CreateFencesAndSeparators(PresContext());
michael@0 69
michael@0 70 return nsMathMLContainerFrame::
michael@0 71 AttributeChanged(aNameSpaceID, aAttribute, aModType);
michael@0 72 }
michael@0 73
michael@0 74 nsresult
michael@0 75 nsMathMLmfencedFrame::ChildListChanged(int32_t aModType)
michael@0 76 {
michael@0 77 RemoveFencesAndSeparators();
michael@0 78 CreateFencesAndSeparators(PresContext());
michael@0 79
michael@0 80 return nsMathMLContainerFrame::ChildListChanged(aModType);
michael@0 81 }
michael@0 82
michael@0 83 void
michael@0 84 nsMathMLmfencedFrame::RemoveFencesAndSeparators()
michael@0 85 {
michael@0 86 delete mOpenChar;
michael@0 87 delete mCloseChar;
michael@0 88 if (mSeparatorsChar) delete[] mSeparatorsChar;
michael@0 89
michael@0 90 mOpenChar = nullptr;
michael@0 91 mCloseChar = nullptr;
michael@0 92 mSeparatorsChar = nullptr;
michael@0 93 mSeparatorsCount = 0;
michael@0 94 }
michael@0 95
michael@0 96 void
michael@0 97 nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
michael@0 98 {
michael@0 99 nsAutoString value;
michael@0 100
michael@0 101 //////////////
michael@0 102 // see if the opening fence is there ...
michael@0 103 if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::open, value)) {
michael@0 104 value = char16_t('('); // default as per the MathML REC
michael@0 105 } else {
michael@0 106 value.CompressWhitespace();
michael@0 107 }
michael@0 108
michael@0 109 if (!value.IsEmpty()) {
michael@0 110 mOpenChar = new nsMathMLChar;
michael@0 111 mOpenChar->SetData(aPresContext, value);
michael@0 112 ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar);
michael@0 113 }
michael@0 114
michael@0 115 //////////////
michael@0 116 // see if the closing fence is there ...
michael@0 117 if(!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::close, value)) {
michael@0 118 value = char16_t(')'); // default as per the MathML REC
michael@0 119 } else {
michael@0 120 value.CompressWhitespace();
michael@0 121 }
michael@0 122
michael@0 123 if (!value.IsEmpty()) {
michael@0 124 mCloseChar = new nsMathMLChar;
michael@0 125 mCloseChar->SetData(aPresContext, value);
michael@0 126 ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar);
michael@0 127 }
michael@0 128
michael@0 129 //////////////
michael@0 130 // see if separators are there ...
michael@0 131 if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separators_, value)) {
michael@0 132 value = char16_t(','); // default as per the MathML REC
michael@0 133 } else {
michael@0 134 value.StripWhitespace();
michael@0 135 }
michael@0 136
michael@0 137 mSeparatorsCount = value.Length();
michael@0 138 if (0 < mSeparatorsCount) {
michael@0 139 int32_t sepCount = mFrames.GetLength() - 1;
michael@0 140 if (0 < sepCount) {
michael@0 141 mSeparatorsChar = new nsMathMLChar[sepCount];
michael@0 142 nsAutoString sepChar;
michael@0 143 for (int32_t i = 0; i < sepCount; i++) {
michael@0 144 if (i < mSeparatorsCount) {
michael@0 145 sepChar = value[i];
michael@0 146 }
michael@0 147 else {
michael@0 148 sepChar = value[mSeparatorsCount-1];
michael@0 149 }
michael@0 150 mSeparatorsChar[i].SetData(aPresContext, sepChar);
michael@0 151 ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i]);
michael@0 152 }
michael@0 153 mSeparatorsCount = sepCount;
michael@0 154 } else {
michael@0 155 // No separators. Note that sepCount can be -1 here, so don't
michael@0 156 // set mSeparatorsCount to it.
michael@0 157 mSeparatorsCount = 0;
michael@0 158 }
michael@0 159 }
michael@0 160 }
michael@0 161
michael@0 162 void
michael@0 163 nsMathMLmfencedFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 164 const nsRect& aDirtyRect,
michael@0 165 const nsDisplayListSet& aLists)
michael@0 166 {
michael@0 167 /////////////
michael@0 168 // display the content
michael@0 169 nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
michael@0 170
michael@0 171 ////////////
michael@0 172 // display fences and separators
michael@0 173 uint32_t count = 0;
michael@0 174 if (mOpenChar) {
michael@0 175 mOpenChar->Display(aBuilder, this, aLists, count++);
michael@0 176 }
michael@0 177
michael@0 178 if (mCloseChar) {
michael@0 179 mCloseChar->Display(aBuilder, this, aLists, count++);
michael@0 180 }
michael@0 181
michael@0 182 for (int32_t i = 0; i < mSeparatorsCount; i++) {
michael@0 183 mSeparatorsChar[i].Display(aBuilder, this, aLists, count++);
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 nsresult
michael@0 188 nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext,
michael@0 189 nsHTMLReflowMetrics& aDesiredSize,
michael@0 190 const nsHTMLReflowState& aReflowState,
michael@0 191 nsReflowStatus& aStatus)
michael@0 192 {
michael@0 193 nsresult rv;
michael@0 194 aDesiredSize.Width() = aDesiredSize.Height() = 0;
michael@0 195 aDesiredSize.SetTopAscent(0);
michael@0 196 aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
michael@0 197
michael@0 198 int32_t i;
michael@0 199 const nsStyleFont* font = StyleFont();
michael@0 200 nsRefPtr<nsFontMetrics> fm;
michael@0 201 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
michael@0 202 aReflowState.rendContext->SetFont(fm);
michael@0 203 nscoord axisHeight, em;
michael@0 204 GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
michael@0 205 GetEmHeight(fm, em);
michael@0 206 // leading to be left at the top and the bottom of stretched chars
michael@0 207 nscoord leading = NSToCoordRound(0.2f * em);
michael@0 208
michael@0 209 /////////////
michael@0 210 // Reflow children
michael@0 211 // Asking each child to cache its bounding metrics
michael@0 212
michael@0 213 // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
michael@0 214 // because we want to stretch our fences, separators and stretchy frames using
michael@0 215 // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
michael@0 216 // method here, our stretchy frames will be stretched and placed, and we may
michael@0 217 // end up stretching our fences/separators with a different aDesiredSize.
michael@0 218 // XXX The above decision was revisited in bug 121748 and this code can be
michael@0 219 // refactored to use nsMathMLContainerFrame::Reflow() at some stage.
michael@0 220
michael@0 221 nsReflowStatus childStatus;
michael@0 222 nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
michael@0 223 nsIFrame* firstChild = GetFirstPrincipalChild();
michael@0 224 nsIFrame* childFrame = firstChild;
michael@0 225 nscoord ascent = 0, descent = 0;
michael@0 226 if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) {
michael@0 227 // We use the ASCII metrics to get our minimum height. This way,
michael@0 228 // if we have borders or a background, they will fit better with
michael@0 229 // other elements on the line.
michael@0 230 ascent = fm->MaxAscent();
michael@0 231 descent = fm->MaxDescent();
michael@0 232 }
michael@0 233 while (childFrame) {
michael@0 234 nsHTMLReflowMetrics childDesiredSize(aReflowState,
michael@0 235 aDesiredSize.mFlags
michael@0 236 | NS_REFLOW_CALC_BOUNDING_METRICS);
michael@0 237 nsHTMLReflowState childReflowState(aPresContext, aReflowState,
michael@0 238 childFrame, availSize);
michael@0 239 rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
michael@0 240 childReflowState, childStatus);
michael@0 241 //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
michael@0 242 if (NS_FAILED(rv)) {
michael@0 243 // Call DidReflow() for the child frames we successfully did reflow.
michael@0 244 DidReflowChildren(firstChild, childFrame);
michael@0 245 return rv;
michael@0 246 }
michael@0 247
michael@0 248 SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
michael@0 249 childDesiredSize.mBoundingMetrics);
michael@0 250
michael@0 251 nscoord childDescent = childDesiredSize.Height() - childDesiredSize.TopAscent();
michael@0 252 if (descent < childDescent)
michael@0 253 descent = childDescent;
michael@0 254 if (ascent < childDesiredSize.TopAscent())
michael@0 255 ascent = childDesiredSize.TopAscent();
michael@0 256
michael@0 257 childFrame = childFrame->GetNextSibling();
michael@0 258 }
michael@0 259
michael@0 260 /////////////
michael@0 261 // Ask stretchy children to stretch themselves
michael@0 262
michael@0 263 nsBoundingMetrics containerSize;
michael@0 264 nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;
michael@0 265
michael@0 266 GetPreferredStretchSize(*aReflowState.rendContext,
michael@0 267 0, /* i.e., without embellishments */
michael@0 268 stretchDir, containerSize);
michael@0 269 childFrame = firstChild;
michael@0 270 while (childFrame) {
michael@0 271 nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame);
michael@0 272 if (mathmlChild) {
michael@0 273 nsHTMLReflowMetrics childDesiredSize(aReflowState);
michael@0 274 // retrieve the metrics that was stored at the previous pass
michael@0 275 GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
michael@0 276 childDesiredSize.mBoundingMetrics);
michael@0 277
michael@0 278 mathmlChild->Stretch(*aReflowState.rendContext,
michael@0 279 stretchDir, containerSize, childDesiredSize);
michael@0 280 // store the updated metrics
michael@0 281 SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
michael@0 282 childDesiredSize.mBoundingMetrics);
michael@0 283
michael@0 284 nscoord childDescent = childDesiredSize.Height() - childDesiredSize.TopAscent();
michael@0 285 if (descent < childDescent)
michael@0 286 descent = childDescent;
michael@0 287 if (ascent < childDesiredSize.TopAscent())
michael@0 288 ascent = childDesiredSize.TopAscent();
michael@0 289 }
michael@0 290 childFrame = childFrame->GetNextSibling();
michael@0 291 }
michael@0 292
michael@0 293 // bug 121748: for surrounding fences & separators, use a size that covers everything
michael@0 294 GetPreferredStretchSize(*aReflowState.rendContext,
michael@0 295 STRETCH_CONSIDER_EMBELLISHMENTS,
michael@0 296 stretchDir, containerSize);
michael@0 297
michael@0 298 //////////////////////////////////////////
michael@0 299 // Prepare the opening fence, separators, and closing fence, and
michael@0 300 // adjust the origin of children.
michael@0 301
michael@0 302 // we need to center around the axis
michael@0 303 nscoord delta = std::max(containerSize.ascent - axisHeight,
michael@0 304 containerSize.descent + axisHeight);
michael@0 305 containerSize.ascent = delta + axisHeight;
michael@0 306 containerSize.descent = delta - axisHeight;
michael@0 307
michael@0 308 bool isRTL = StyleVisibility()->mDirection;
michael@0 309
michael@0 310 /////////////////
michael@0 311 // opening fence ...
michael@0 312 ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar,
michael@0 313 NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel,
michael@0 314 axisHeight, leading, em, containerSize, ascent, descent, isRTL);
michael@0 315 /////////////////
michael@0 316 // separators ...
michael@0 317 for (i = 0; i < mSeparatorsCount; i++) {
michael@0 318 ReflowChar(aPresContext, *aReflowState.rendContext, &mSeparatorsChar[i],
michael@0 319 NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
michael@0 320 axisHeight, leading, em, containerSize, ascent, descent, isRTL);
michael@0 321 }
michael@0 322 /////////////////
michael@0 323 // closing fence ...
michael@0 324 ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar,
michael@0 325 NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
michael@0 326 axisHeight, leading, em, containerSize, ascent, descent, isRTL);
michael@0 327
michael@0 328 //////////////////
michael@0 329 // Adjust the origins of each child.
michael@0 330 // and update our bounding metrics
michael@0 331
michael@0 332 i = 0;
michael@0 333 nscoord dx = 0;
michael@0 334 nsBoundingMetrics bm;
michael@0 335 bool firstTime = true;
michael@0 336 nsMathMLChar *leftChar, *rightChar;
michael@0 337 if (isRTL) {
michael@0 338 leftChar = mCloseChar;
michael@0 339 rightChar = mOpenChar;
michael@0 340 } else {
michael@0 341 leftChar = mOpenChar;
michael@0 342 rightChar = mCloseChar;
michael@0 343 }
michael@0 344
michael@0 345 if (leftChar) {
michael@0 346 PlaceChar(leftChar, ascent, bm, dx);
michael@0 347 aDesiredSize.mBoundingMetrics = bm;
michael@0 348 firstTime = false;
michael@0 349 }
michael@0 350
michael@0 351 if (isRTL) {
michael@0 352 childFrame = this->GetLastChild(nsIFrame::kPrincipalList);
michael@0 353 } else {
michael@0 354 childFrame = firstChild;
michael@0 355 }
michael@0 356 while (childFrame) {
michael@0 357 nsHTMLReflowMetrics childSize(aReflowState);
michael@0 358 GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
michael@0 359 if (firstTime) {
michael@0 360 firstTime = false;
michael@0 361 aDesiredSize.mBoundingMetrics = bm;
michael@0 362 }
michael@0 363 else
michael@0 364 aDesiredSize.mBoundingMetrics += bm;
michael@0 365
michael@0 366 FinishReflowChild(childFrame, aPresContext, childSize, nullptr,
michael@0 367 dx, ascent - childSize.TopAscent(), 0);
michael@0 368 dx += childSize.Width();
michael@0 369
michael@0 370 if (i < mSeparatorsCount) {
michael@0 371 PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i],
michael@0 372 ascent, bm, dx);
michael@0 373 aDesiredSize.mBoundingMetrics += bm;
michael@0 374 }
michael@0 375 i++;
michael@0 376
michael@0 377 if (isRTL) {
michael@0 378 childFrame = childFrame->GetPrevSibling();
michael@0 379 } else {
michael@0 380 childFrame = childFrame->GetNextSibling();
michael@0 381 }
michael@0 382 }
michael@0 383
michael@0 384 if (rightChar) {
michael@0 385 PlaceChar(rightChar, ascent, bm, dx);
michael@0 386 if (firstTime)
michael@0 387 aDesiredSize.mBoundingMetrics = bm;
michael@0 388 else
michael@0 389 aDesiredSize.mBoundingMetrics += bm;
michael@0 390 }
michael@0 391
michael@0 392 aDesiredSize.Width() = aDesiredSize.mBoundingMetrics.width;
michael@0 393 aDesiredSize.Height() = ascent + descent;
michael@0 394 aDesiredSize.SetTopAscent(ascent);
michael@0 395
michael@0 396 SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
michael@0 397 SetReference(nsPoint(0, aDesiredSize.TopAscent()));
michael@0 398
michael@0 399 // see if we should fix the spacing
michael@0 400 FixInterFrameSpacing(aDesiredSize);
michael@0 401
michael@0 402 // Finished with these:
michael@0 403 ClearSavedChildMetrics();
michael@0 404
michael@0 405 // Set our overflow area
michael@0 406 GatherAndStoreOverflow(&aDesiredSize);
michael@0 407
michael@0 408 aStatus = NS_FRAME_COMPLETE;
michael@0 409 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 410 return NS_OK;
michael@0 411 }
michael@0 412
michael@0 413 static void
michael@0 414 GetCharSpacing(nsMathMLChar* aMathMLChar,
michael@0 415 nsOperatorFlags aForm,
michael@0 416 int32_t aScriptLevel,
michael@0 417 nscoord em,
michael@0 418 nscoord& aLeftSpace,
michael@0 419 nscoord& aRightSpace)
michael@0 420 {
michael@0 421 nsAutoString data;
michael@0 422 aMathMLChar->GetData(data);
michael@0 423 nsOperatorFlags flags = 0;
michael@0 424 float lspace = 0.0f;
michael@0 425 float rspace = 0.0f;
michael@0 426 bool found = nsMathMLOperators::LookupOperator(data, aForm,
michael@0 427 &flags, &lspace, &rspace);
michael@0 428
michael@0 429 // We don't want extra space when we are a script
michael@0 430 if (found && aScriptLevel > 0) {
michael@0 431 lspace /= 2.0f;
michael@0 432 rspace /= 2.0f;
michael@0 433 }
michael@0 434
michael@0 435 aLeftSpace = NSToCoordRound(lspace * em);
michael@0 436 aRightSpace = NSToCoordRound(rspace * em);
michael@0 437 }
michael@0 438
michael@0 439 // helper functions to perform the common task of formatting our chars
michael@0 440 /*static*/ nsresult
michael@0 441 nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
michael@0 442 nsRenderingContext& aRenderingContext,
michael@0 443 nsMathMLChar* aMathMLChar,
michael@0 444 nsOperatorFlags aForm,
michael@0 445 int32_t aScriptLevel,
michael@0 446 nscoord axisHeight,
michael@0 447 nscoord leading,
michael@0 448 nscoord em,
michael@0 449 nsBoundingMetrics& aContainerSize,
michael@0 450 nscoord& aAscent,
michael@0 451 nscoord& aDescent,
michael@0 452 bool aRTL)
michael@0 453 {
michael@0 454 if (aMathMLChar && 0 < aMathMLChar->Length()) {
michael@0 455 nscoord leftSpace;
michael@0 456 nscoord rightSpace;
michael@0 457 GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
michael@0 458
michael@0 459 // stretch the char to the appropriate height if it is not big enough.
michael@0 460 nsBoundingMetrics charSize;
michael@0 461 nsresult res = aMathMLChar->Stretch(aPresContext, aRenderingContext,
michael@0 462 NS_STRETCH_DIRECTION_VERTICAL,
michael@0 463 aContainerSize, charSize,
michael@0 464 NS_STRETCH_NORMAL, aRTL);
michael@0 465
michael@0 466 if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) {
michael@0 467 // has changed... so center the char around the axis
michael@0 468 nscoord height = charSize.ascent + charSize.descent;
michael@0 469 charSize.ascent = height/2 + axisHeight;
michael@0 470 charSize.descent = height - charSize.ascent;
michael@0 471 }
michael@0 472 else {
michael@0 473 // either it hasn't changed or stretching the char failed (i.e.,
michael@0 474 // GetBoundingMetrics failed)
michael@0 475 leading = 0;
michael@0 476 if (NS_FAILED(res)) {
michael@0 477 nsAutoString data;
michael@0 478 aMathMLChar->GetData(data);
michael@0 479 nsBoundingMetrics metrics =
michael@0 480 aRenderingContext.GetBoundingMetrics(data.get(), data.Length());
michael@0 481 charSize.ascent = metrics.ascent;
michael@0 482 charSize.descent = metrics.descent;
michael@0 483 charSize.width = metrics.width;
michael@0 484 // Set this as the bounding metrics of the MathMLChar to leave
michael@0 485 // the necessary room to paint the char.
michael@0 486 aMathMLChar->SetBoundingMetrics(charSize);
michael@0 487 }
michael@0 488 }
michael@0 489
michael@0 490 if (aAscent < charSize.ascent + leading)
michael@0 491 aAscent = charSize.ascent + leading;
michael@0 492 if (aDescent < charSize.descent + leading)
michael@0 493 aDescent = charSize.descent + leading;
michael@0 494
michael@0 495 // account the spacing
michael@0 496 charSize.width += leftSpace + rightSpace;
michael@0 497
michael@0 498 // x-origin is used to store lspace ...
michael@0 499 // y-origin is used to stored the ascent ...
michael@0 500 aMathMLChar->SetRect(nsRect(leftSpace,
michael@0 501 charSize.ascent, charSize.width,
michael@0 502 charSize.ascent + charSize.descent));
michael@0 503 }
michael@0 504 return NS_OK;
michael@0 505 }
michael@0 506
michael@0 507 /*static*/ void
michael@0 508 nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar,
michael@0 509 nscoord aDesiredAscent,
michael@0 510 nsBoundingMetrics& bm,
michael@0 511 nscoord& dx)
michael@0 512 {
michael@0 513 aMathMLChar->GetBoundingMetrics(bm);
michael@0 514
michael@0 515 // the char's x-origin was used to store lspace ...
michael@0 516 // the char's y-origin was used to store the ascent ...
michael@0 517 // the char's width was used to store the advance with (with spacing) ...
michael@0 518 nsRect rect;
michael@0 519 aMathMLChar->GetRect(rect);
michael@0 520
michael@0 521 nscoord dy = aDesiredAscent - rect.y;
michael@0 522 if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) {
michael@0 523 // the stretchy char will be centered around the axis
michael@0 524 // so we adjust the returned bounding metrics accordingly
michael@0 525 bm.descent = (bm.ascent + bm.descent) - rect.y;
michael@0 526 bm.ascent = rect.y;
michael@0 527 }
michael@0 528
michael@0 529 aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height));
michael@0 530
michael@0 531 bm.leftBearing += rect.x;
michael@0 532 bm.rightBearing += rect.x;
michael@0 533
michael@0 534 // return rect.width since it includes lspace and rspace
michael@0 535 bm.width = rect.width;
michael@0 536 dx += rect.width;
michael@0 537 }
michael@0 538
michael@0 539 static nscoord
michael@0 540 GetMaxCharWidth(nsPresContext* aPresContext,
michael@0 541 nsRenderingContext* aRenderingContext,
michael@0 542 nsMathMLChar* aMathMLChar,
michael@0 543 nsOperatorFlags aForm,
michael@0 544 int32_t aScriptLevel,
michael@0 545 nscoord em)
michael@0 546 {
michael@0 547 nscoord width = aMathMLChar->GetMaxWidth(aPresContext, *aRenderingContext);
michael@0 548
michael@0 549 if (0 < aMathMLChar->Length()) {
michael@0 550 nscoord leftSpace;
michael@0 551 nscoord rightSpace;
michael@0 552 GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
michael@0 553
michael@0 554 width += leftSpace + rightSpace;
michael@0 555 }
michael@0 556
michael@0 557 return width;
michael@0 558 }
michael@0 559
michael@0 560 /* virtual */ void
michael@0 561 nsMathMLmfencedFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize)
michael@0 562 {
michael@0 563 nscoord width = 0;
michael@0 564
michael@0 565 nsPresContext* presContext = PresContext();
michael@0 566 const nsStyleFont* font = StyleFont();
michael@0 567 nsRefPtr<nsFontMetrics> fm;
michael@0 568 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
michael@0 569 nscoord em;
michael@0 570 GetEmHeight(fm, em);
michael@0 571
michael@0 572 if (mOpenChar) {
michael@0 573 width +=
michael@0 574 GetMaxCharWidth(presContext, aRenderingContext, mOpenChar,
michael@0 575 NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em);
michael@0 576 }
michael@0 577
michael@0 578 int32_t i = 0;
michael@0 579 nsIFrame* childFrame = GetFirstPrincipalChild();
michael@0 580 while (childFrame) {
michael@0 581 // XXX This includes margin while Reflow currently doesn't consider
michael@0 582 // margin, so we may end up with too much space, but, with stretchy
michael@0 583 // characters, this is an approximation anyway.
michael@0 584 width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
michael@0 585 nsLayoutUtils::PREF_WIDTH);
michael@0 586
michael@0 587 if (i < mSeparatorsCount) {
michael@0 588 width +=
michael@0 589 GetMaxCharWidth(presContext, aRenderingContext, &mSeparatorsChar[i],
michael@0 590 NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em);
michael@0 591 }
michael@0 592 i++;
michael@0 593
michael@0 594 childFrame = childFrame->GetNextSibling();
michael@0 595 }
michael@0 596
michael@0 597 if (mCloseChar) {
michael@0 598 width +=
michael@0 599 GetMaxCharWidth(presContext, aRenderingContext, mCloseChar,
michael@0 600 NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em);
michael@0 601 }
michael@0 602
michael@0 603 aDesiredSize.Width() = width;
michael@0 604 aDesiredSize.mBoundingMetrics.width = width;
michael@0 605 aDesiredSize.mBoundingMetrics.leftBearing = 0;
michael@0 606 aDesiredSize.mBoundingMetrics.rightBearing = width;
michael@0 607 }
michael@0 608
michael@0 609 nscoord
michael@0 610 nsMathMLmfencedFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
michael@0 611 {
michael@0 612 nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
michael@0 613 if (!gap) return 0;
michael@0 614
michael@0 615 nsRect rect;
michael@0 616 if (mOpenChar) {
michael@0 617 mOpenChar->GetRect(rect);
michael@0 618 rect.MoveBy(gap, 0);
michael@0 619 mOpenChar->SetRect(rect);
michael@0 620 }
michael@0 621 if (mCloseChar) {
michael@0 622 mCloseChar->GetRect(rect);
michael@0 623 rect.MoveBy(gap, 0);
michael@0 624 mCloseChar->SetRect(rect);
michael@0 625 }
michael@0 626 for (int32_t i = 0; i < mSeparatorsCount; i++) {
michael@0 627 mSeparatorsChar[i].GetRect(rect);
michael@0 628 rect.MoveBy(gap, 0);
michael@0 629 mSeparatorsChar[i].SetRect(rect);
michael@0 630 }
michael@0 631 return gap;
michael@0 632 }
michael@0 633
michael@0 634 // ----------------------
michael@0 635 // the Style System will use these to pass the proper style context to our MathMLChar
michael@0 636 nsStyleContext*
michael@0 637 nsMathMLmfencedFrame::GetAdditionalStyleContext(int32_t aIndex) const
michael@0 638 {
michael@0 639 int32_t openIndex = -1;
michael@0 640 int32_t closeIndex = -1;
michael@0 641 int32_t lastIndex = mSeparatorsCount-1;
michael@0 642
michael@0 643 if (mOpenChar) {
michael@0 644 lastIndex++;
michael@0 645 openIndex = lastIndex;
michael@0 646 }
michael@0 647 if (mCloseChar) {
michael@0 648 lastIndex++;
michael@0 649 closeIndex = lastIndex;
michael@0 650 }
michael@0 651 if (aIndex < 0 || aIndex > lastIndex) {
michael@0 652 return nullptr;
michael@0 653 }
michael@0 654
michael@0 655 if (aIndex < mSeparatorsCount) {
michael@0 656 return mSeparatorsChar[aIndex].GetStyleContext();
michael@0 657 }
michael@0 658 else if (aIndex == openIndex) {
michael@0 659 return mOpenChar->GetStyleContext();
michael@0 660 }
michael@0 661 else if (aIndex == closeIndex) {
michael@0 662 return mCloseChar->GetStyleContext();
michael@0 663 }
michael@0 664 return nullptr;
michael@0 665 }
michael@0 666
michael@0 667 void
michael@0 668 nsMathMLmfencedFrame::SetAdditionalStyleContext(int32_t aIndex,
michael@0 669 nsStyleContext* aStyleContext)
michael@0 670 {
michael@0 671 int32_t openIndex = -1;
michael@0 672 int32_t closeIndex = -1;
michael@0 673 int32_t lastIndex = mSeparatorsCount-1;
michael@0 674
michael@0 675 if (mOpenChar) {
michael@0 676 lastIndex++;
michael@0 677 openIndex = lastIndex;
michael@0 678 }
michael@0 679 if (mCloseChar) {
michael@0 680 lastIndex++;
michael@0 681 closeIndex = lastIndex;
michael@0 682 }
michael@0 683 if (aIndex < 0 || aIndex > lastIndex) {
michael@0 684 return;
michael@0 685 }
michael@0 686
michael@0 687 if (aIndex < mSeparatorsCount) {
michael@0 688 mSeparatorsChar[aIndex].SetStyleContext(aStyleContext);
michael@0 689 }
michael@0 690 else if (aIndex == openIndex) {
michael@0 691 mOpenChar->SetStyleContext(aStyleContext);
michael@0 692 }
michael@0 693 else if (aIndex == closeIndex) {
michael@0 694 mCloseChar->SetStyleContext(aStyleContext);
michael@0 695 }
michael@0 696 }

mercurial