layout/mathml/nsMathMLmunderoverFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
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 #include "nsMathMLmunderoverFrame.h"
michael@0 7 #include "nsPresContext.h"
michael@0 8 #include "nsRenderingContext.h"
michael@0 9 #include "nsMathMLmmultiscriptsFrame.h"
michael@0 10 #include <algorithm>
michael@0 11
michael@0 12 //
michael@0 13 // <munderover> -- attach an underscript-overscript pair to a base - implementation
michael@0 14 // <mover> -- attach an overscript to a base - implementation
michael@0 15 // <munder> -- attach an underscript to a base - implementation
michael@0 16 //
michael@0 17
michael@0 18 nsIFrame*
michael@0 19 NS_NewMathMLmunderoverFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 20 {
michael@0 21 return new (aPresShell) nsMathMLmunderoverFrame(aContext);
michael@0 22 }
michael@0 23
michael@0 24 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmunderoverFrame)
michael@0 25
michael@0 26 nsMathMLmunderoverFrame::~nsMathMLmunderoverFrame()
michael@0 27 {
michael@0 28 }
michael@0 29
michael@0 30 nsresult
michael@0 31 nsMathMLmunderoverFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 32 nsIAtom* aAttribute,
michael@0 33 int32_t aModType)
michael@0 34 {
michael@0 35 if (nsGkAtoms::accent_ == aAttribute ||
michael@0 36 nsGkAtoms::accentunder_ == aAttribute) {
michael@0 37 // When we have automatic data to update within ourselves, we ask our
michael@0 38 // parent to re-layout its children
michael@0 39 return ReLayoutChildren(mParent);
michael@0 40 }
michael@0 41
michael@0 42 return nsMathMLContainerFrame::
michael@0 43 AttributeChanged(aNameSpaceID, aAttribute, aModType);
michael@0 44 }
michael@0 45
michael@0 46 NS_IMETHODIMP
michael@0 47 nsMathMLmunderoverFrame::UpdatePresentationData(uint32_t aFlagsValues,
michael@0 48 uint32_t aFlagsToUpdate)
michael@0 49 {
michael@0 50 nsMathMLContainerFrame::UpdatePresentationData(aFlagsValues, aFlagsToUpdate);
michael@0 51 // disable the stretch-all flag if we are going to act like a subscript-superscript pair
michael@0 52 if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
michael@0 53 StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
michael@0 54 mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
michael@0 55 }
michael@0 56 else {
michael@0 57 mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
michael@0 58 }
michael@0 59 return NS_OK;
michael@0 60 }
michael@0 61
michael@0 62 NS_IMETHODIMP
michael@0 63 nsMathMLmunderoverFrame::InheritAutomaticData(nsIFrame* aParent)
michael@0 64 {
michael@0 65 // let the base class get the default from our parent
michael@0 66 nsMathMLContainerFrame::InheritAutomaticData(aParent);
michael@0 67
michael@0 68 mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
michael@0 69
michael@0 70 return NS_OK;
michael@0 71 }
michael@0 72
michael@0 73 uint8_t
michael@0 74 nsMathMLmunderoverFrame::ScriptIncrement(nsIFrame* aFrame)
michael@0 75 {
michael@0 76 nsIFrame* child = mFrames.FirstChild();
michael@0 77 if (!aFrame || aFrame == child) {
michael@0 78 return 0;
michael@0 79 }
michael@0 80 child = child->GetNextSibling();
michael@0 81 if (aFrame == child) {
michael@0 82 if (mContent->Tag() == nsGkAtoms::mover_) {
michael@0 83 return mIncrementOver ? 1 : 0;
michael@0 84 }
michael@0 85 return mIncrementUnder ? 1 : 0;
michael@0 86 }
michael@0 87 if (child && aFrame == child->GetNextSibling()) {
michael@0 88 // must be a over frame of munderover
michael@0 89 return mIncrementOver ? 1 : 0;
michael@0 90 }
michael@0 91 return 0; // frame not found
michael@0 92 }
michael@0 93
michael@0 94 NS_IMETHODIMP
michael@0 95 nsMathMLmunderoverFrame::TransmitAutomaticData()
michael@0 96 {
michael@0 97 // At this stage, all our children are in sync and we can fully
michael@0 98 // resolve our own mEmbellishData struct
michael@0 99 //---------------------------------------------------------------------
michael@0 100
michael@0 101 /*
michael@0 102 The REC says:
michael@0 103
michael@0 104 As regards munder (respectively mover) :
michael@0 105 The default value of accentunder is false, unless underscript
michael@0 106 is an <mo> element or an embellished operator. If underscript is
michael@0 107 an <mo> element, the value of its accent attribute is used as the
michael@0 108 default value of accentunder. If underscript is an embellished
michael@0 109 operator, the accent attribute of the <mo> element at its
michael@0 110 core is used as the default value. As with all attributes, an
michael@0 111 explicitly given value overrides the default.
michael@0 112
michael@0 113 XXX The winner is the outermost setting in conflicting settings like these:
michael@0 114 <munder accentunder='true'>
michael@0 115 <mi>...</mi>
michael@0 116 <mo accentunder='false'> ... </mo>
michael@0 117 </munder>
michael@0 118
michael@0 119 As regards munderover:
michael@0 120 The accent and accentunder attributes have the same effect as
michael@0 121 the attributes with the same names on <mover> and <munder>,
michael@0 122 respectively. Their default values are also computed in the
michael@0 123 same manner as described for those elements, with the default
michael@0 124 value of accent depending on overscript and the default value
michael@0 125 of accentunder depending on underscript.
michael@0 126 */
michael@0 127
michael@0 128 nsIFrame* overscriptFrame = nullptr;
michael@0 129 nsIFrame* underscriptFrame = nullptr;
michael@0 130 nsIFrame* baseFrame = mFrames.FirstChild();
michael@0 131 nsIAtom* tag = mContent->Tag();
michael@0 132
michael@0 133 if (baseFrame) {
michael@0 134 if (tag == nsGkAtoms::munder_ ||
michael@0 135 tag == nsGkAtoms::munderover_) {
michael@0 136 underscriptFrame = baseFrame->GetNextSibling();
michael@0 137 } else {
michael@0 138 NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized");
michael@0 139 overscriptFrame = baseFrame->GetNextSibling();
michael@0 140 }
michael@0 141 }
michael@0 142 if (underscriptFrame &&
michael@0 143 tag == nsGkAtoms::munderover_) {
michael@0 144 overscriptFrame = underscriptFrame->GetNextSibling();
michael@0 145
michael@0 146 }
michael@0 147
michael@0 148 // if our base is an embellished operator, let its state bubble to us (in particular,
michael@0 149 // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags
michael@0 150 // are reset to the default values of false if the base frame isn't embellished.
michael@0 151 mPresentationData.baseFrame = baseFrame;
michael@0 152 GetEmbellishDataFrom(baseFrame, mEmbellishData);
michael@0 153
michael@0 154 // The default value of accentunder is false, unless the underscript is embellished
michael@0 155 // and its core <mo> is an accent
michael@0 156 nsEmbellishData embellishData;
michael@0 157 nsAutoString value;
michael@0 158 if (tag == nsGkAtoms::munder_ ||
michael@0 159 tag == nsGkAtoms::munderover_) {
michael@0 160 GetEmbellishDataFrom(underscriptFrame, embellishData);
michael@0 161 if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) {
michael@0 162 mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
michael@0 163 } else {
michael@0 164 mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
michael@0 165 }
michael@0 166
michael@0 167 // if we have an accentunder attribute, it overrides what the underscript said
michael@0 168 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accentunder_, value)) {
michael@0 169 if (value.EqualsLiteral("true")) {
michael@0 170 mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
michael@0 171 } else if (value.EqualsLiteral("false")) {
michael@0 172 mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
michael@0 173 }
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 // The default value of accent is false, unless the overscript is embellished
michael@0 178 // and its core <mo> is an accent
michael@0 179 if (tag == nsGkAtoms::mover_ ||
michael@0 180 tag == nsGkAtoms::munderover_) {
michael@0 181 GetEmbellishDataFrom(overscriptFrame, embellishData);
michael@0 182 if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) {
michael@0 183 mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
michael@0 184 } else {
michael@0 185 mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
michael@0 186 }
michael@0 187
michael@0 188 // if we have an accent attribute, it overrides what the overscript said
michael@0 189 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value)) {
michael@0 190 if (value.EqualsLiteral("true")) {
michael@0 191 mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
michael@0 192 } else if (value.EqualsLiteral("false")) {
michael@0 193 mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
michael@0 194 }
michael@0 195 }
michael@0 196 }
michael@0 197
michael@0 198 bool subsupDisplay =
michael@0 199 NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
michael@0 200 StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE;
michael@0 201
michael@0 202 // disable the stretch-all flag if we are going to act like a superscript
michael@0 203 if (subsupDisplay) {
michael@0 204 mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
michael@0 205 }
michael@0 206
michael@0 207 // Now transmit any change that we want to our children so that they
michael@0 208 // can update their mPresentationData structs
michael@0 209 //---------------------------------------------------------------------
michael@0 210
michael@0 211 /* The REC says:
michael@0 212 Within underscript, <munderover> always sets displaystyle to "false",
michael@0 213 but increments scriptlevel by 1 only when accentunder is "false".
michael@0 214
michael@0 215 Within overscript, <munderover> always sets displaystyle to "false",
michael@0 216 but increments scriptlevel by 1 only when accent is "false".
michael@0 217
michael@0 218 Within subscript and superscript it increments scriptlevel by 1, and
michael@0 219 sets displaystyle to "false", but leaves both attributes unchanged within
michael@0 220 base.
michael@0 221
michael@0 222 The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a
michael@0 223 say it shouldn't be compressed. However, The TeXBook says
michael@0 224 that math accents and \overline change uncramped styles to their
michael@0 225 cramped counterparts.
michael@0 226 */
michael@0 227 if (tag == nsGkAtoms::mover_ ||
michael@0 228 tag == nsGkAtoms::munderover_) {
michael@0 229 uint32_t compress = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)
michael@0 230 ? NS_MATHML_COMPRESSED : 0;
michael@0 231 mIncrementOver =
michael@0 232 !NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) ||
michael@0 233 subsupDisplay;
michael@0 234 SetIncrementScriptLevel(tag == nsGkAtoms::mover_ ? 1 : 2, mIncrementOver);
michael@0 235 if (mIncrementOver) {
michael@0 236 PropagateFrameFlagFor(overscriptFrame,
michael@0 237 NS_FRAME_MATHML_SCRIPT_DESCENDANT);
michael@0 238 }
michael@0 239 PropagatePresentationDataFor(overscriptFrame, compress, compress);
michael@0 240 }
michael@0 241 /*
michael@0 242 The TeXBook treats 'under' like a subscript, so p.141 or Rule 13a
michael@0 243 say it should be compressed
michael@0 244 */
michael@0 245 if (tag == nsGkAtoms::munder_ ||
michael@0 246 tag == nsGkAtoms::munderover_) {
michael@0 247 mIncrementUnder =
michael@0 248 !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags) ||
michael@0 249 subsupDisplay;
michael@0 250 SetIncrementScriptLevel(1, mIncrementUnder);
michael@0 251 if (mIncrementUnder) {
michael@0 252 PropagateFrameFlagFor(underscriptFrame,
michael@0 253 NS_FRAME_MATHML_SCRIPT_DESCENDANT);
michael@0 254 }
michael@0 255 PropagatePresentationDataFor(underscriptFrame,
michael@0 256 NS_MATHML_COMPRESSED,
michael@0 257 NS_MATHML_COMPRESSED);
michael@0 258 }
michael@0 259 return NS_OK;
michael@0 260 }
michael@0 261
michael@0 262 /*
michael@0 263 The REC says:
michael@0 264 * If the base is an operator with movablelimits="true" (or an embellished
michael@0 265 operator whose <mo> element core has movablelimits="true"), and
michael@0 266 displaystyle="false", then underscript and overscript are drawn in
michael@0 267 a subscript and superscript position, respectively. In this case,
michael@0 268 the accent and accentunder attributes are ignored. This is often
michael@0 269 used for limits on symbols such as &sum;.
michael@0 270
michael@0 271 i.e.,:
michael@0 272 if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishDataflags) &&
michael@0 273 StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
michael@0 274 // place like subscript-superscript pair
michael@0 275 }
michael@0 276 else {
michael@0 277 // place like underscript-overscript pair
michael@0 278 }
michael@0 279 */
michael@0 280
michael@0 281 /* virtual */ nsresult
michael@0 282 nsMathMLmunderoverFrame::Place(nsRenderingContext& aRenderingContext,
michael@0 283 bool aPlaceOrigin,
michael@0 284 nsHTMLReflowMetrics& aDesiredSize)
michael@0 285 {
michael@0 286 nsIAtom* tag = mContent->Tag();
michael@0 287 if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
michael@0 288 StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
michael@0 289 //place like sub sup or subsup
michael@0 290 nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
michael@0 291 if (tag == nsGkAtoms::munderover_) {
michael@0 292 return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
michael@0 293 aRenderingContext,
michael@0 294 aPlaceOrigin,
michael@0 295 aDesiredSize,
michael@0 296 this, 0, 0,
michael@0 297 scriptSpace);
michael@0 298 } else if (tag == nsGkAtoms::munder_) {
michael@0 299 return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
michael@0 300 aRenderingContext,
michael@0 301 aPlaceOrigin,
michael@0 302 aDesiredSize,
michael@0 303 this, 0, 0,
michael@0 304 scriptSpace);
michael@0 305 } else {
michael@0 306 NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized");
michael@0 307 return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
michael@0 308 aRenderingContext,
michael@0 309 aPlaceOrigin,
michael@0 310 aDesiredSize,
michael@0 311 this, 0, 0,
michael@0 312 scriptSpace);
michael@0 313 }
michael@0 314
michael@0 315 }
michael@0 316
michael@0 317 ////////////////////////////////////
michael@0 318 // Get the children's desired sizes
michael@0 319
michael@0 320 nsBoundingMetrics bmBase, bmUnder, bmOver;
michael@0 321 nsHTMLReflowMetrics baseSize(aDesiredSize.GetWritingMode());
michael@0 322 nsHTMLReflowMetrics underSize(aDesiredSize.GetWritingMode());
michael@0 323 nsHTMLReflowMetrics overSize(aDesiredSize.GetWritingMode());
michael@0 324 nsIFrame* overFrame = nullptr;
michael@0 325 nsIFrame* underFrame = nullptr;
michael@0 326 nsIFrame* baseFrame = mFrames.FirstChild();
michael@0 327 underSize.SetTopAscent(0);
michael@0 328 overSize.SetTopAscent(0);
michael@0 329 bool haveError = false;
michael@0 330 if (baseFrame) {
michael@0 331 if (tag == nsGkAtoms::munder_ ||
michael@0 332 tag == nsGkAtoms::munderover_) {
michael@0 333 underFrame = baseFrame->GetNextSibling();
michael@0 334 } else if (tag == nsGkAtoms::mover_) {
michael@0 335 overFrame = baseFrame->GetNextSibling();
michael@0 336 }
michael@0 337 }
michael@0 338 if (underFrame && tag == nsGkAtoms::munderover_) {
michael@0 339 overFrame = underFrame->GetNextSibling();
michael@0 340 }
michael@0 341
michael@0 342 if (tag == nsGkAtoms::munder_) {
michael@0 343 if (!baseFrame || !underFrame || underFrame->GetNextSibling()) {
michael@0 344 // report an error, encourage people to get their markups in order
michael@0 345 haveError = true;
michael@0 346 }
michael@0 347 }
michael@0 348 if (tag == nsGkAtoms::mover_) {
michael@0 349 if (!baseFrame || !overFrame || overFrame->GetNextSibling()) {
michael@0 350 // report an error, encourage people to get their markups in order
michael@0 351 haveError = true;
michael@0 352 }
michael@0 353 }
michael@0 354 if (tag == nsGkAtoms::munderover_) {
michael@0 355 if (!baseFrame || !underFrame || !overFrame || overFrame->GetNextSibling()) {
michael@0 356 // report an error, encourage people to get their markups in order
michael@0 357 haveError = true;
michael@0 358 }
michael@0 359 }
michael@0 360 if (haveError) {
michael@0 361 if (aPlaceOrigin) {
michael@0 362 ReportChildCountError();
michael@0 363 }
michael@0 364 return ReflowError(aRenderingContext, aDesiredSize);
michael@0 365 }
michael@0 366 GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
michael@0 367 if (underFrame) {
michael@0 368 GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder);
michael@0 369 }
michael@0 370 if (overFrame) {
michael@0 371 GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver);
michael@0 372 }
michael@0 373
michael@0 374 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
michael@0 375
michael@0 376 ////////////////////
michael@0 377 // Place Children
michael@0 378
michael@0 379 nsRefPtr<nsFontMetrics> fm;
michael@0 380 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
michael@0 381 aRenderingContext.SetFont(fm);
michael@0 382
michael@0 383 nscoord xHeight = fm->XHeight();
michael@0 384
michael@0 385 nscoord ruleThickness;
michael@0 386 GetRuleThickness (aRenderingContext, fm, ruleThickness);
michael@0 387
michael@0 388 nscoord correction = 0;
michael@0 389 GetItalicCorrection (bmBase, correction);
michael@0 390
michael@0 391 // there are 2 different types of placement depending on
michael@0 392 // whether we want an accented under or not
michael@0 393
michael@0 394 nscoord underDelta1 = 0; // gap between base and underscript
michael@0 395 nscoord underDelta2 = 0; // extra space beneath underscript
michael@0 396
michael@0 397 if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
michael@0 398 // Rule 13a, App. G, TeXbook
michael@0 399 nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy;
michael@0 400 GetBigOpSpacings (fm,
michael@0 401 dummy, bigOpSpacing2,
michael@0 402 dummy, bigOpSpacing4,
michael@0 403 bigOpSpacing5);
michael@0 404 underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent));
michael@0 405 underDelta2 = bigOpSpacing5;
michael@0 406 }
michael@0 407 else {
michael@0 408 // No corresponding rule in TeXbook - we are on our own here
michael@0 409 // XXX tune the gap delta between base and underscript
michael@0 410
michael@0 411 // Should we use Rule 10 like \underline does?
michael@0 412 underDelta1 = ruleThickness + onePixel/2;
michael@0 413 underDelta2 = ruleThickness;
michael@0 414 }
michael@0 415 // empty under?
michael@0 416 if (!(bmUnder.ascent + bmUnder.descent)) {
michael@0 417 underDelta1 = 0;
michael@0 418 underDelta2 = 0;
michael@0 419 }
michael@0 420
michael@0 421 nscoord overDelta1 = 0; // gap between base and overscript
michael@0 422 nscoord overDelta2 = 0; // extra space above overscript
michael@0 423
michael@0 424 if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
michael@0 425 // Rule 13a, App. G, TeXbook
michael@0 426 nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy;
michael@0 427 GetBigOpSpacings (fm,
michael@0 428 bigOpSpacing1, dummy,
michael@0 429 bigOpSpacing3, dummy,
michael@0 430 bigOpSpacing5);
michael@0 431 overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent));
michael@0 432 overDelta2 = bigOpSpacing5;
michael@0 433
michael@0 434 // XXX This is not a TeX rule...
michael@0 435 // delta1 (as computed abvove) can become really big when bmOver.descent is
michael@0 436 // negative, e.g., if the content is &OverBar. In such case, we use the height
michael@0 437 if (bmOver.descent < 0)
michael@0 438 overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent)));
michael@0 439 }
michael@0 440 else {
michael@0 441 // Rule 12, App. G, TeXbook
michael@0 442 // We are going to modify this rule to make it more general.
michael@0 443 // The idea behind Rule 12 in the TeXBook is to keep the accent
michael@0 444 // as close to the base as possible, while ensuring that the
michael@0 445 // distance between the *baseline* of the accent char and
michael@0 446 // the *baseline* of the base is atleast x-height.
michael@0 447 // The idea is that for normal use, we would like all the accents
michael@0 448 // on a line to line up atleast x-height above the baseline
michael@0 449 // if possible.
michael@0 450 // When the ascent of the base is >= x-height,
michael@0 451 // the baseline of the accent char is placed just above the base
michael@0 452 // (specifically, the baseline of the accent char is placed
michael@0 453 // above the baseline of the base by the ascent of the base).
michael@0 454 // For ease of implementation,
michael@0 455 // this assumes that the font-designer designs accents
michael@0 456 // in such a way that the bottom of the accent is atleast x-height
michael@0 457 // above its baseline, otherwise there will be collisions
michael@0 458 // with the base. Also there should be proper padding between
michael@0 459 // the bottom of the accent char and its baseline.
michael@0 460 // The above rule may not be obvious from a first
michael@0 461 // reading of rule 12 in the TeXBook !!!
michael@0 462 // The mathml <mover> tag can use accent chars that
michael@0 463 // do not follow this convention. So we modify TeX's rule
michael@0 464 // so that TeX's rule gets subsumed for accents that follow
michael@0 465 // TeX's convention,
michael@0 466 // while also allowing accents that do not follow the convention :
michael@0 467 // we try to keep the *bottom* of the accent char atleast x-height
michael@0 468 // from the baseline of the base char. we also slap on an extra
michael@0 469 // padding between the accent and base chars.
michael@0 470 overDelta1 = ruleThickness + onePixel/2;
michael@0 471 if (bmBase.ascent < xHeight) {
michael@0 472 // also ensure at least x-height above the baseline of the base
michael@0 473 overDelta1 += xHeight - bmBase.ascent;
michael@0 474 }
michael@0 475 overDelta2 = ruleThickness;
michael@0 476 }
michael@0 477 // empty over?
michael@0 478 if (!(bmOver.ascent + bmOver.descent)) {
michael@0 479 overDelta1 = 0;
michael@0 480 overDelta2 = 0;
michael@0 481 }
michael@0 482
michael@0 483 nscoord dxBase = 0, dxOver = 0, dxUnder = 0;
michael@0 484 nsAutoString valueAlign;
michael@0 485 enum {
michael@0 486 center,
michael@0 487 left,
michael@0 488 right
michael@0 489 } alignPosition = center;
michael@0 490
michael@0 491 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, valueAlign)) {
michael@0 492 if (valueAlign.EqualsLiteral("left")) {
michael@0 493 alignPosition = left;
michael@0 494 } else if (valueAlign.EqualsLiteral("right")) {
michael@0 495 alignPosition = right;
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 //////////
michael@0 500 // pass 1, do what <mover> does: attach the overscript on the base
michael@0 501
michael@0 502 // Ad-hoc - This is to override fonts which have ready-made _accent_
michael@0 503 // glyphs with negative lbearing and rbearing. We want to position
michael@0 504 // the overscript ourselves
michael@0 505 nscoord overWidth = bmOver.width;
michael@0 506 if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) {
michael@0 507 overWidth = bmOver.rightBearing - bmOver.leftBearing;
michael@0 508 dxOver = -bmOver.leftBearing;
michael@0 509 }
michael@0 510
michael@0 511 if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
michael@0 512 mBoundingMetrics.width = bmBase.width;
michael@0 513 if (alignPosition == center) {
michael@0 514 dxOver += correction;
michael@0 515 }
michael@0 516 }
michael@0 517 else {
michael@0 518 mBoundingMetrics.width = std::max(bmBase.width, overWidth);
michael@0 519 if (alignPosition == center) {
michael@0 520 dxOver += correction/2;
michael@0 521 }
michael@0 522 }
michael@0 523
michael@0 524 if (alignPosition == center) {
michael@0 525 dxOver += (mBoundingMetrics.width - overWidth)/2;
michael@0 526 dxBase = (mBoundingMetrics.width - bmBase.width)/2;
michael@0 527 } else if (alignPosition == right) {
michael@0 528 dxOver += mBoundingMetrics.width - overWidth;
michael@0 529 dxBase = mBoundingMetrics.width - bmBase.width;
michael@0 530 }
michael@0 531
michael@0 532 mBoundingMetrics.ascent =
michael@0 533 bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent;
michael@0 534 mBoundingMetrics.descent = bmBase.descent;
michael@0 535 mBoundingMetrics.leftBearing =
michael@0 536 std::min(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
michael@0 537 mBoundingMetrics.rightBearing =
michael@0 538 std::max(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);
michael@0 539
michael@0 540 //////////
michael@0 541 // pass 2, do what <munder> does: attach the underscript on the previous
michael@0 542 // result. We conceptually view the previous result as an "anynomous base"
michael@0 543 // from where to attach the underscript. Hence if the underscript is empty,
michael@0 544 // we should end up like <mover>. If the overscript is empty, we should
michael@0 545 // end up like <munder>.
michael@0 546
michael@0 547 nsBoundingMetrics bmAnonymousBase = mBoundingMetrics;
michael@0 548 nscoord ascentAnonymousBase =
michael@0 549 std::max(mBoundingMetrics.ascent + overDelta2,
michael@0 550 overSize.TopAscent() + bmOver.descent + overDelta1 + bmBase.ascent);
michael@0 551 ascentAnonymousBase = std::max(ascentAnonymousBase, baseSize.TopAscent());
michael@0 552
michael@0 553 // Width of non-spacing marks is zero so use left and right bearing.
michael@0 554 nscoord underWidth = bmUnder.width;
michael@0 555 if (!underWidth) {
michael@0 556 underWidth = bmUnder.rightBearing - bmUnder.leftBearing;
michael@0 557 dxUnder = -bmUnder.leftBearing;
michael@0 558 }
michael@0 559
michael@0 560 nscoord maxWidth = std::max(bmAnonymousBase.width, underWidth);
michael@0 561 if (alignPosition == center &&
michael@0 562 !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
michael@0 563 GetItalicCorrection(bmAnonymousBase, correction);
michael@0 564 dxUnder += -correction/2;
michael@0 565 }
michael@0 566 nscoord dxAnonymousBase = 0;
michael@0 567 if (alignPosition == center) {
michael@0 568 dxUnder += (maxWidth - underWidth)/2;
michael@0 569 dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2;
michael@0 570 } else if (alignPosition == right) {
michael@0 571 dxUnder += maxWidth - underWidth;
michael@0 572 dxAnonymousBase = maxWidth - bmAnonymousBase.width;
michael@0 573 }
michael@0 574
michael@0 575 // adjust the offsets of the real base and overscript since their
michael@0 576 // final offsets should be relative to us...
michael@0 577 dxOver += dxAnonymousBase;
michael@0 578 dxBase += dxAnonymousBase;
michael@0 579
michael@0 580 mBoundingMetrics.width =
michael@0 581 std::max(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width);
michael@0 582 // At this point, mBoundingMetrics.ascent = bmAnonymousBase.ascent
michael@0 583 mBoundingMetrics.descent =
michael@0 584 bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent;
michael@0 585 mBoundingMetrics.leftBearing =
michael@0 586 std::min(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing);
michael@0 587 mBoundingMetrics.rightBearing =
michael@0 588 std::max(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing);
michael@0 589
michael@0 590 aDesiredSize.SetTopAscent(ascentAnonymousBase);
michael@0 591 aDesiredSize.Height() = aDesiredSize.TopAscent() +
michael@0 592 std::max(mBoundingMetrics.descent + underDelta2,
michael@0 593 bmAnonymousBase.descent + underDelta1 + bmUnder.ascent +
michael@0 594 underSize.Height() - underSize.TopAscent());
michael@0 595 aDesiredSize.Height() = std::max(aDesiredSize.Height(),
michael@0 596 aDesiredSize.TopAscent() +
michael@0 597 baseSize.Height() - baseSize.TopAscent());
michael@0 598 aDesiredSize.Width() = mBoundingMetrics.width;
michael@0 599 aDesiredSize.mBoundingMetrics = mBoundingMetrics;
michael@0 600
michael@0 601 mReference.x = 0;
michael@0 602 mReference.y = aDesiredSize.TopAscent();
michael@0 603
michael@0 604 if (aPlaceOrigin) {
michael@0 605 nscoord dy;
michael@0 606 // place overscript
michael@0 607 if (overFrame) {
michael@0 608 dy = aDesiredSize.TopAscent() - mBoundingMetrics.ascent + bmOver.ascent
michael@0 609 - overSize.TopAscent();
michael@0 610 FinishReflowChild (overFrame, PresContext(), overSize, nullptr, dxOver, dy, 0);
michael@0 611 }
michael@0 612 // place base
michael@0 613 dy = aDesiredSize.TopAscent() - baseSize.TopAscent();
michael@0 614 FinishReflowChild (baseFrame, PresContext(), baseSize, nullptr, dxBase, dy, 0);
michael@0 615 // place underscript
michael@0 616 if (underFrame) {
michael@0 617 dy = aDesiredSize.TopAscent() + mBoundingMetrics.descent - bmUnder.descent
michael@0 618 - underSize.TopAscent();
michael@0 619 FinishReflowChild (underFrame, PresContext(), underSize, nullptr,
michael@0 620 dxUnder, dy, 0);
michael@0 621 }
michael@0 622 }
michael@0 623 return NS_OK;
michael@0 624 }

mercurial