layout/mathml/nsMathMLmmultiscriptsFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 "nsMathMLmmultiscriptsFrame.h"
michael@0 8 #include "nsPresContext.h"
michael@0 9 #include "nsRenderingContext.h"
michael@0 10 #include <algorithm>
michael@0 11
michael@0 12 using mozilla::WritingMode;
michael@0 13
michael@0 14 //
michael@0 15 // <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation
michael@0 16 // <msub> -- attach a subscript to a base - implementation
michael@0 17 // <msubsup> -- attach a subscript-superscript pair to a base - implementation
michael@0 18 // <msup> -- attach a superscript to a base - implementation
michael@0 19 //
michael@0 20
michael@0 21 nsIFrame*
michael@0 22 NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 23 {
michael@0 24 return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext);
michael@0 25 }
michael@0 26
michael@0 27 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame)
michael@0 28
michael@0 29 nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame()
michael@0 30 {
michael@0 31 }
michael@0 32
michael@0 33 uint8_t
michael@0 34 nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame* aFrame)
michael@0 35 {
michael@0 36 if (!aFrame)
michael@0 37 return 0;
michael@0 38 if (mFrames.ContainsFrame(aFrame)) {
michael@0 39 if (mFrames.FirstChild() == aFrame ||
michael@0 40 aFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) {
michael@0 41 return 0; // No script increment for base frames or prescript markers
michael@0 42 }
michael@0 43 return 1;
michael@0 44 }
michael@0 45 return 0; //not a child
michael@0 46 }
michael@0 47
michael@0 48 NS_IMETHODIMP
michael@0 49 nsMathMLmmultiscriptsFrame::TransmitAutomaticData()
michael@0 50 {
michael@0 51 // if our base is an embellished operator, let its state bubble to us
michael@0 52 mPresentationData.baseFrame = mFrames.FirstChild();
michael@0 53 GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
michael@0 54
michael@0 55 // The TeXbook (Ch 17. p.141) says the superscript inherits the compression
michael@0 56 // while the subscript is compressed. So here we collect subscripts and set
michael@0 57 // the compression flag in them.
michael@0 58
michael@0 59 int32_t count = 0;
michael@0 60 bool isSubScript = mContent->Tag() != nsGkAtoms::msup_;
michael@0 61
michael@0 62 nsAutoTArray<nsIFrame*, 8> subScriptFrames;
michael@0 63 nsIFrame* childFrame = mFrames.FirstChild();
michael@0 64 while (childFrame) {
michael@0 65 if (childFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) {
michael@0 66 // mprescripts frame
michael@0 67 } else if (0 == count) {
michael@0 68 // base frame
michael@0 69 } else {
michael@0 70 // super/subscript block
michael@0 71 if (isSubScript) {
michael@0 72 // subscript
michael@0 73 subScriptFrames.AppendElement(childFrame);
michael@0 74 } else {
michael@0 75 // superscript
michael@0 76 }
michael@0 77 PropagateFrameFlagFor(childFrame, NS_FRAME_MATHML_SCRIPT_DESCENDANT);
michael@0 78 isSubScript = !isSubScript;
michael@0 79 }
michael@0 80 count++;
michael@0 81 childFrame = childFrame->GetNextSibling();
michael@0 82 }
michael@0 83 for (int32_t i = subScriptFrames.Length() - 1; i >= 0; i--) {
michael@0 84 childFrame = subScriptFrames[i];
michael@0 85 PropagatePresentationDataFor(childFrame,
michael@0 86 NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED);
michael@0 87 }
michael@0 88
michael@0 89 return NS_OK;
michael@0 90 }
michael@0 91
michael@0 92 /* virtual */ nsresult
michael@0 93 nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext,
michael@0 94 bool aPlaceOrigin,
michael@0 95 nsHTMLReflowMetrics& aDesiredSize)
michael@0 96 {
michael@0 97 nscoord subScriptShift = 0;
michael@0 98 nscoord supScriptShift = 0;
michael@0 99 nsIAtom* tag = mContent->Tag();
michael@0 100
michael@0 101 // subscriptshift
michael@0 102 //
michael@0 103 // "Specifies the minimum amount to shift the baseline of subscript down; the
michael@0 104 // default is for the rendering agent to use its own positioning rules."
michael@0 105 //
michael@0 106 // values: length
michael@0 107 // default: automatic
michael@0 108 //
michael@0 109 // We use 0 as the default value so unitless values can be ignored.
michael@0 110 // As a minimum, negative values can be ignored.
michael@0 111 //
michael@0 112 nsAutoString value;
michael@0 113 if (tag != nsGkAtoms::msup_) {
michael@0 114 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::subscriptshift_, value);
michael@0 115 if (!value.IsEmpty()) {
michael@0 116 ParseNumericValue(value, &subScriptShift, 0, PresContext(),
michael@0 117 mStyleContext);
michael@0 118 }
michael@0 119 }
michael@0 120 // superscriptshift
michael@0 121 //
michael@0 122 // "Specifies the minimum amount to shift the baseline of superscript up; the
michael@0 123 // default is for the rendering agent to use its own positioning rules."
michael@0 124 //
michael@0 125 // values: length
michael@0 126 // default: automatic
michael@0 127 //
michael@0 128 // We use 0 as the default value so unitless values can be ignored.
michael@0 129 // As a minimum, negative values can be ignored.
michael@0 130 //
michael@0 131 if (tag != nsGkAtoms::msub_) {
michael@0 132 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value);
michael@0 133 if (!value.IsEmpty()) {
michael@0 134 ParseNumericValue(value, &supScriptShift, 0, PresContext(),
michael@0 135 mStyleContext);
michael@0 136 }
michael@0 137 }
michael@0 138 // scriptspace from TeX for extra spacing after sup/subscript
michael@0 139 // (0.5pt in plain TeX)
michael@0 140 nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
michael@0 141
michael@0 142 return PlaceMultiScript(PresContext(), aRenderingContext, aPlaceOrigin,
michael@0 143 aDesiredSize, this, subScriptShift, supScriptShift,
michael@0 144 scriptSpace);
michael@0 145 }
michael@0 146
michael@0 147 // exported routine that both munderover and mmultiscripts share.
michael@0 148 // munderover uses this when movablelimits is set.
michael@0 149 nsresult
michael@0 150 nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext* aPresContext,
michael@0 151 nsRenderingContext& aRenderingContext,
michael@0 152 bool aPlaceOrigin,
michael@0 153 nsHTMLReflowMetrics& aDesiredSize,
michael@0 154 nsMathMLContainerFrame* aFrame,
michael@0 155 nscoord aUserSubScriptShift,
michael@0 156 nscoord aUserSupScriptShift,
michael@0 157 nscoord aScriptSpace)
michael@0 158 {
michael@0 159 nsIAtom* tag = aFrame->GetContent()->Tag();
michael@0 160
michael@0 161 // This function deals with both munderover etc. as well as msubsup etc.
michael@0 162 // As the former behaves identically to the later, we treat it as such
michael@0 163 // to avoid additional checks later.
michael@0 164 if (tag == nsGkAtoms::mover_)
michael@0 165 tag = nsGkAtoms::msup_;
michael@0 166 else if (tag == nsGkAtoms::munder_)
michael@0 167 tag = nsGkAtoms::msub_;
michael@0 168 else if (tag == nsGkAtoms::munderover_)
michael@0 169 tag = nsGkAtoms::msubsup_;
michael@0 170
michael@0 171 nsBoundingMetrics bmFrame;
michael@0 172
michael@0 173 nscoord minShiftFromXHeight, subDrop, supDrop;
michael@0 174
michael@0 175 ////////////////////////////////////////
michael@0 176 // Initialize super/sub shifts that
michael@0 177 // depend only on the current font
michael@0 178 ////////////////////////////////////////
michael@0 179
michael@0 180 nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
michael@0 181
michael@0 182 if (!baseFrame) {
michael@0 183 if (tag == nsGkAtoms::mmultiscripts_)
michael@0 184 aFrame->ReportErrorToConsole("NoBase");
michael@0 185 else
michael@0 186 aFrame->ReportChildCountError();
michael@0 187 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
michael@0 188 }
michael@0 189
michael@0 190
michael@0 191 // get x-height (an ex)
michael@0 192 const nsStyleFont* font = aFrame->StyleFont();
michael@0 193 nsRefPtr<nsFontMetrics> fm;
michael@0 194 nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
michael@0 195 aRenderingContext.SetFont(fm);
michael@0 196
michael@0 197 nscoord xHeight = fm->XHeight();
michael@0 198
michael@0 199 nscoord ruleSize;
michael@0 200 GetRuleThickness (aRenderingContext, fm, ruleSize);
michael@0 201
michael@0 202 // force the scriptSpace to be at least 1 pixel
michael@0 203 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
michael@0 204 aScriptSpace = std::max(onePixel, aScriptSpace);
michael@0 205
michael@0 206 /////////////////////////////////////
michael@0 207 // first the shift for the subscript
michael@0 208
michael@0 209 // subScriptShift{1,2}
michael@0 210 // = minimum amount to shift the subscript down
michael@0 211 // = sub{1,2} in TeXbook
michael@0 212 // subScriptShift1 = subscriptshift attribute * x-height
michael@0 213 nscoord subScriptShift1, subScriptShift2;
michael@0 214
michael@0 215 // Get subScriptShift{1,2} default from font
michael@0 216 GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
michael@0 217 nscoord subScriptShift;
michael@0 218 if (tag == nsGkAtoms::msub_) {
michael@0 219 subScriptShift = subScriptShift1;
michael@0 220 } else {
michael@0 221 subScriptShift = std::max(subScriptShift1, subScriptShift2);
michael@0 222 }
michael@0 223 if (0 < aUserSubScriptShift) {
michael@0 224 // the user has set the subscriptshift attribute
michael@0 225 subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
michael@0 226 }
michael@0 227
michael@0 228 /////////////////////////////////////
michael@0 229 // next the shift for the superscript
michael@0 230
michael@0 231 // supScriptShift{1,2,3}
michael@0 232 // = minimum amount to shift the supscript up
michael@0 233 // = sup{1,2,3} in TeX
michael@0 234 // supScriptShift1 = superscriptshift attribute * x-height
michael@0 235 // Note that there are THREE values for supscript shifts depending
michael@0 236 // on the current style
michael@0 237 nscoord supScriptShift1, supScriptShift2, supScriptShift3;
michael@0 238 // Set supScriptShift{1,2,3} default from font
michael@0 239 GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
michael@0 240
michael@0 241 // get sup script shift depending on current script level and display style
michael@0 242 // Rule 18c, App. G, TeXbook
michael@0 243 nsPresentationData presentationData;
michael@0 244 aFrame->GetPresentationData(presentationData);
michael@0 245 nscoord supScriptShift;
michael@0 246 if (font->mScriptLevel == 0 &&
michael@0 247 font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
michael@0 248 !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
michael@0 249 // Style D in TeXbook
michael@0 250 supScriptShift = supScriptShift1;
michael@0 251 } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
michael@0 252 // Style C' in TeXbook = D',T',S',SS'
michael@0 253 supScriptShift = supScriptShift3;
michael@0 254 } else {
michael@0 255 // everything else = T,S,SS
michael@0 256 supScriptShift = supScriptShift2;
michael@0 257 }
michael@0 258
michael@0 259 if (0 < aUserSupScriptShift) {
michael@0 260 // the user has set the supscriptshift attribute
michael@0 261 supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
michael@0 262 }
michael@0 263
michael@0 264 ////////////////////////////////////
michael@0 265 // Get the children's sizes
michael@0 266 ////////////////////////////////////
michael@0 267
michael@0 268 const WritingMode wm(aDesiredSize.GetWritingMode());
michael@0 269 nscoord width = 0, prescriptsWidth = 0, rightBearing = 0;
michael@0 270 nscoord minSubScriptShift = 0, minSupScriptShift = 0;
michael@0 271 nscoord trySubScriptShift = subScriptShift;
michael@0 272 nscoord trySupScriptShift = supScriptShift;
michael@0 273 nscoord maxSubScriptShift = subScriptShift;
michael@0 274 nscoord maxSupScriptShift = supScriptShift;
michael@0 275 nsHTMLReflowMetrics baseSize(wm);
michael@0 276 nsHTMLReflowMetrics subScriptSize(wm);
michael@0 277 nsHTMLReflowMetrics supScriptSize(wm);
michael@0 278 nsHTMLReflowMetrics multiSubSize(wm), multiSupSize(wm);
michael@0 279 baseFrame = nullptr;
michael@0 280 nsIFrame* subScriptFrame = nullptr;
michael@0 281 nsIFrame* supScriptFrame = nullptr;
michael@0 282 nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there.
michael@0 283
michael@0 284 bool firstPrescriptsPair = false;
michael@0 285 nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup;
michael@0 286 multiSubSize.SetTopAscent(-0x7FFFFFFF);
michael@0 287 multiSupSize.SetTopAscent(-0x7FFFFFFF);
michael@0 288 bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF;
michael@0 289 bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF;
michael@0 290 nscoord italicCorrection = 0;
michael@0 291
michael@0 292 nsBoundingMetrics boundingMetrics;
michael@0 293 boundingMetrics.width = 0;
michael@0 294 boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF;
michael@0 295 aDesiredSize.Width() = aDesiredSize.Height() = 0;
michael@0 296
michael@0 297 int32_t count = 0;
michael@0 298 bool foundNoneTag = false;
michael@0 299
michael@0 300 // Boolean to determine whether the current child is a subscript.
michael@0 301 // Note that only msup starts with a superscript.
michael@0 302 bool isSubScript = (tag != nsGkAtoms::msup_);
michael@0 303
michael@0 304 nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
michael@0 305 while (childFrame) {
michael@0 306 nsIAtom* childTag = childFrame->GetContent()->Tag();
michael@0 307 if (childTag == nsGkAtoms::mprescripts_) {
michael@0 308 if (tag != nsGkAtoms::mmultiscripts_) {
michael@0 309 if (aPlaceOrigin) {
michael@0 310 aFrame->ReportInvalidChildError(childTag);
michael@0 311 }
michael@0 312 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
michael@0 313 }
michael@0 314 if (prescriptsFrame) {
michael@0 315 // duplicate <mprescripts/> found
michael@0 316 // report an error, encourage people to get their markups in order
michael@0 317 if (aPlaceOrigin) {
michael@0 318 aFrame->ReportErrorToConsole("DuplicateMprescripts");
michael@0 319 }
michael@0 320 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
michael@0 321 }
michael@0 322 if (!isSubScript) {
michael@0 323 if (aPlaceOrigin) {
michael@0 324 aFrame->ReportErrorToConsole("SubSupMismatch");
michael@0 325 }
michael@0 326 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
michael@0 327 }
michael@0 328
michael@0 329 prescriptsFrame = childFrame;
michael@0 330 firstPrescriptsPair = true;
michael@0 331 } else if (0 == count) {
michael@0 332 // base
michael@0 333
michael@0 334 if (childTag == nsGkAtoms::none) {
michael@0 335 if (tag == nsGkAtoms::mmultiscripts_) {
michael@0 336 if (aPlaceOrigin) {
michael@0 337 aFrame->ReportErrorToConsole("NoBase");
michael@0 338 }
michael@0 339 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
michael@0 340 } else {
michael@0 341 //A different error message is triggered later for the other tags
michael@0 342 foundNoneTag = true;
michael@0 343 }
michael@0 344 }
michael@0 345 baseFrame = childFrame;
michael@0 346 GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
michael@0 347
michael@0 348 if (tag != nsGkAtoms::msub_) {
michael@0 349 // Apply italics correction if there is the potential for a
michael@0 350 // postsupscript.
michael@0 351 GetItalicCorrection(bmBase, italicCorrection);
michael@0 352 // If italics correction is applied, we always add "a little to spare"
michael@0 353 // (see TeXbook Ch.11, p.64), as we estimate the italic creation
michael@0 354 // ourselves and it isn't the same as TeX.
michael@0 355 italicCorrection += onePixel;
michael@0 356 }
michael@0 357
michael@0 358 // we update boundingMetrics.{ascent,descent} with that
michael@0 359 // of the baseFrame only after processing all the sup/sub pairs
michael@0 360 boundingMetrics.width = bmBase.width;
michael@0 361 boundingMetrics.rightBearing = bmBase.rightBearing;
michael@0 362 boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
michael@0 363 } else {
michael@0 364 // super/subscript block
michael@0 365 if ( childTag == nsGkAtoms::none) {
michael@0 366 foundNoneTag = true;
michael@0 367 }
michael@0 368
michael@0 369 if (isSubScript) {
michael@0 370 // subscript
michael@0 371 subScriptFrame = childFrame;
michael@0 372 GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
michael@0 373 // get the subdrop from the subscript font
michael@0 374 GetSubDropFromChild (subScriptFrame, subDrop);
michael@0 375 // parameter v, Rule 18a, App. G, TeXbook
michael@0 376 minSubScriptShift = bmBase.descent + subDrop;
michael@0 377 trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
michael@0 378 multiSubSize.SetTopAscent(std::max(multiSubSize.TopAscent(),
michael@0 379 subScriptSize.TopAscent()));
michael@0 380 bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent);
michael@0 381 bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent);
michael@0 382 multiSubSize.Height() =
michael@0 383 std::max(multiSubSize.Height(),
michael@0 384 subScriptSize.Height() - subScriptSize.TopAscent());
michael@0 385 if (bmSubScript.width)
michael@0 386 width = bmSubScript.width + aScriptSpace;
michael@0 387 rightBearing = bmSubScript.rightBearing;
michael@0 388
michael@0 389 if (tag == nsGkAtoms::msub_) {
michael@0 390 boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
michael@0 391 boundingMetrics.width += width;
michael@0 392
michael@0 393 // get min subscript shift limit from x-height
michael@0 394 // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
michael@0 395 nscoord minShiftFromXHeight = (nscoord)
michael@0 396 (bmSubScript.ascent - (4.0f/5.0f) * xHeight);
michael@0 397 maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
michael@0 398
michael@0 399 maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
michael@0 400 trySubScriptShift = subScriptShift;
michael@0 401 }
michael@0 402 } else {
michael@0 403 // supscript
michael@0 404 supScriptFrame = childFrame;
michael@0 405 GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
michael@0 406 // get the supdrop from the supscript font
michael@0 407 GetSupDropFromChild (supScriptFrame, supDrop);
michael@0 408 // parameter u, Rule 18a, App. G, TeXbook
michael@0 409 minSupScriptShift = bmBase.ascent - supDrop;
michael@0 410 // get min supscript shift limit from x-height
michael@0 411 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
michael@0 412 minShiftFromXHeight = NSToCoordRound
michael@0 413 ((bmSupScript.descent + (1.0f/4.0f) * xHeight));
michael@0 414 trySupScriptShift = std::max(minSupScriptShift,
michael@0 415 std::max(minShiftFromXHeight,
michael@0 416 supScriptShift));
michael@0 417 multiSupSize.SetTopAscent(std::max(multiSupSize.TopAscent(),
michael@0 418 supScriptSize.TopAscent()));
michael@0 419 bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
michael@0 420 bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
michael@0 421 multiSupSize.Height() =
michael@0 422 std::max(multiSupSize.Height(),
michael@0 423 supScriptSize.Height() - supScriptSize.TopAscent());
michael@0 424
michael@0 425 if (bmSupScript.width)
michael@0 426 width = std::max(width, bmSupScript.width + aScriptSpace);
michael@0 427
michael@0 428 if (!prescriptsFrame) { // we are still looping over base & postscripts
michael@0 429 rightBearing = std::max(rightBearing,
michael@0 430 italicCorrection + bmSupScript.rightBearing);
michael@0 431 boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
michael@0 432 boundingMetrics.width += width;
michael@0 433 } else {
michael@0 434 prescriptsWidth += width;
michael@0 435 if (firstPrescriptsPair) {
michael@0 436 firstPrescriptsPair = false;
michael@0 437 boundingMetrics.leftBearing =
michael@0 438 std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
michael@0 439 }
michael@0 440 }
michael@0 441 width = rightBearing = 0;
michael@0 442
michael@0 443 // negotiate between the various shifts so that
michael@0 444 // there is enough gap between the sup and subscripts
michael@0 445 // Rule 18e, App. G, TeXbook
michael@0 446 if (tag == nsGkAtoms::mmultiscripts_ ||
michael@0 447 tag == nsGkAtoms::msubsup_) {
michael@0 448 nscoord gap =
michael@0 449 (trySupScriptShift - bmSupScript.descent) -
michael@0 450 (bmSubScript.ascent - trySubScriptShift);
michael@0 451 if (gap < 4.0f * ruleSize) {
michael@0 452 // adjust trySubScriptShift to get a gap of (4.0 * ruleSize)
michael@0 453 trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap);
michael@0 454 }
michael@0 455
michael@0 456 // next we want to ensure that the bottom of the superscript
michael@0 457 // will be > (4/5) * x-height above baseline
michael@0 458 gap = NSToCoordRound ((4.0f/5.0f) * xHeight -
michael@0 459 (trySupScriptShift - bmSupScript.descent));
michael@0 460 if (gap > 0) {
michael@0 461 trySupScriptShift += gap;
michael@0 462 trySubScriptShift -= gap;
michael@0 463 }
michael@0 464 }
michael@0 465
michael@0 466 maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
michael@0 467 maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
michael@0 468
michael@0 469 trySubScriptShift = subScriptShift;
michael@0 470 trySupScriptShift = supScriptShift;
michael@0 471 }
michael@0 472
michael@0 473 isSubScript = !isSubScript;
michael@0 474 }
michael@0 475 count++;
michael@0 476 childFrame = childFrame->GetNextSibling();
michael@0 477 }
michael@0 478
michael@0 479 //NoBase error may also have been reported above
michael@0 480 if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) ||
michael@0 481 (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame ||
michael@0 482 (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) ||
michael@0 483 (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) {
michael@0 484 // report an error, encourage people to get their markups in order
michael@0 485 if (aPlaceOrigin) {
michael@0 486 if ((count != 2 && (tag == nsGkAtoms::msup_ ||
michael@0 487 tag == nsGkAtoms::msub_)) ||
michael@0 488 (count != 3 && tag == nsGkAtoms::msubsup_ )) {
michael@0 489 aFrame->ReportChildCountError();
michael@0 490 } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) {
michael@0 491 aFrame->ReportInvalidChildError(nsGkAtoms::none);
michael@0 492 } else if (!baseFrame) {
michael@0 493 aFrame->ReportErrorToConsole("NoBase");
michael@0 494 } else {
michael@0 495 aFrame->ReportErrorToConsole("SubSupMismatch");
michael@0 496 }
michael@0 497 }
michael@0 498 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
michael@0 499 }
michael@0 500
michael@0 501 // we left out the width of prescripts, so ...
michael@0 502 boundingMetrics.rightBearing += prescriptsWidth;
michael@0 503 boundingMetrics.width += prescriptsWidth;
michael@0 504
michael@0 505 // Zero out the shifts in where a frame isn't present to avoid the potential
michael@0 506 // for overflow.
michael@0 507 if (!subScriptFrame)
michael@0 508 maxSubScriptShift = 0;
michael@0 509 if (!supScriptFrame)
michael@0 510 maxSupScriptShift = 0;
michael@0 511
michael@0 512 // we left out the base during our bounding box updates, so ...
michael@0 513 if (tag == nsGkAtoms::msub_) {
michael@0 514 boundingMetrics.ascent = std::max(bmBase.ascent,
michael@0 515 bmMultiSub.ascent - maxSubScriptShift);
michael@0 516 } else {
michael@0 517 boundingMetrics.ascent =
michael@0 518 std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift));
michael@0 519 }
michael@0 520 if (tag == nsGkAtoms::msup_) {
michael@0 521 boundingMetrics.descent = std::max(bmBase.descent,
michael@0 522 bmMultiSup.descent - maxSupScriptShift);
michael@0 523 } else {
michael@0 524 boundingMetrics.descent =
michael@0 525 std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift));
michael@0 526 }
michael@0 527 aFrame->SetBoundingMetrics(boundingMetrics);
michael@0 528
michael@0 529 // get the reflow metrics ...
michael@0 530 aDesiredSize.SetTopAscent(
michael@0 531 std::max(baseSize.TopAscent(),
michael@0 532 std::max(multiSubSize.TopAscent() - maxSubScriptShift,
michael@0 533 multiSupSize.TopAscent() + maxSupScriptShift)));
michael@0 534 aDesiredSize.Height() = aDesiredSize.TopAscent() +
michael@0 535 std::max(baseSize.Height() - baseSize.TopAscent(),
michael@0 536 std::max(multiSubSize.Height() + maxSubScriptShift,
michael@0 537 multiSupSize.Height() - maxSupScriptShift));
michael@0 538 aDesiredSize.Width() = boundingMetrics.width;
michael@0 539 aDesiredSize.mBoundingMetrics = boundingMetrics;
michael@0 540
michael@0 541 aFrame->SetReference(nsPoint(0, aDesiredSize.TopAscent()));
michael@0 542
michael@0 543 //////////////////
michael@0 544 // Place Children
michael@0 545
michael@0 546 // Place prescripts, followed by base, and then postscripts.
michael@0 547 // The list of frames is in the order: {base} {postscripts} {prescripts}
michael@0 548 // We go over the list in a circular manner, starting at <prescripts/>
michael@0 549
michael@0 550 if (aPlaceOrigin) {
michael@0 551 nscoord dx = 0, dy = 0;
michael@0 552
michael@0 553 // With msub and msup there is only one element and
michael@0 554 // subscriptFrame/supScriptFrame have already been set above where
michael@0 555 // relevant. In these cases we skip to the reflow part.
michael@0 556 if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_)
michael@0 557 count = 1;
michael@0 558 else
michael@0 559 count = 0;
michael@0 560 childFrame = prescriptsFrame;
michael@0 561 bool isPreScript = true;
michael@0 562 do {
michael@0 563 if (!childFrame) { // end of prescripts,
michael@0 564 isPreScript = false;
michael@0 565 // place the base ...
michael@0 566 childFrame = baseFrame;
michael@0 567 dy = aDesiredSize.TopAscent() - baseSize.TopAscent();
michael@0 568 FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr,
michael@0 569 aFrame->MirrorIfRTL(aDesiredSize.Width(),
michael@0 570 baseSize.Width(),
michael@0 571 dx),
michael@0 572 dy, 0);
michael@0 573 dx += bmBase.width;
michael@0 574 } else if (prescriptsFrame == childFrame) {
michael@0 575 // Clear reflow flags of prescripts frame.
michael@0 576 prescriptsFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
michael@0 577 } else {
michael@0 578 // process each sup/sub pair
michael@0 579 if (0 == count) {
michael@0 580 subScriptFrame = childFrame;
michael@0 581 count = 1;
michael@0 582 } else if (1 == count) {
michael@0 583 if (tag != nsGkAtoms::msub_)
michael@0 584 supScriptFrame = childFrame;
michael@0 585 count = 0;
michael@0 586
michael@0 587 // get the ascent/descent of sup/subscripts stored in their rects
michael@0 588 // rect.x = descent, rect.y = ascent
michael@0 589 if (subScriptFrame)
michael@0 590 GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
michael@0 591 if (supScriptFrame)
michael@0 592 GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
michael@0 593
michael@0 594 width = std::max(subScriptSize.Width(), supScriptSize.Width());
michael@0 595
michael@0 596 if (subScriptFrame) {
michael@0 597 nscoord x = dx;
michael@0 598 // prescripts should be right aligned
michael@0 599 // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
michael@0 600 if (isPreScript)
michael@0 601 x += width - subScriptSize.Width();
michael@0 602 dy = aDesiredSize.TopAscent() - subScriptSize.TopAscent() +
michael@0 603 maxSubScriptShift;
michael@0 604 FinishReflowChild (subScriptFrame, aPresContext, subScriptSize,
michael@0 605 nullptr,
michael@0 606 aFrame->MirrorIfRTL(aDesiredSize.Width(),
michael@0 607 subScriptSize.Width(),
michael@0 608 x),
michael@0 609 dy, 0);
michael@0 610 }
michael@0 611
michael@0 612 if (supScriptFrame) {
michael@0 613 nscoord x = dx;
michael@0 614 if (isPreScript) {
michael@0 615 x += width - supScriptSize.Width();
michael@0 616 } else {
michael@0 617 // post superscripts are shifted by the italic correction value
michael@0 618 x += italicCorrection;
michael@0 619 }
michael@0 620 dy = aDesiredSize.TopAscent() - supScriptSize.TopAscent() -
michael@0 621 maxSupScriptShift;
michael@0 622 FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
michael@0 623 nullptr,
michael@0 624 aFrame->MirrorIfRTL(aDesiredSize.Width(),
michael@0 625 supScriptSize.Width(),
michael@0 626 x),
michael@0 627 dy, 0);
michael@0 628 }
michael@0 629 dx += width + aScriptSpace;
michael@0 630 }
michael@0 631 }
michael@0 632 childFrame = childFrame->GetNextSibling();
michael@0 633 } while (prescriptsFrame != childFrame);
michael@0 634 }
michael@0 635
michael@0 636 return NS_OK;
michael@0 637 }

mercurial