1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla MathML Project.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * The University Of Queensland.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Roger B. Sidje <rbs@maths.uq.edu.au>
24 : * David J. Fiddes <D.J.Fiddes@hw.ac.uk>
25 : * Shyjan Mahamud <mahamud@cs.cmu.edu>
26 : * Frederic Wang <fred.wang@free.fr>
27 : * Florian Scholz <elchi3@elchi3.de>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either of the GNU General Public License Version 2 or later (the "GPL"),
31 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 :
44 : #include "nsCOMPtr.h"
45 : #include "nsFrame.h"
46 : #include "nsPresContext.h"
47 : #include "nsStyleContext.h"
48 : #include "nsStyleConsts.h"
49 : #include "nsRenderingContext.h"
50 :
51 : #include "nsMathMLmfracFrame.h"
52 : #include "nsDisplayList.h"
53 : #include "gfxContext.h"
54 :
55 : //
56 : // <mfrac> -- form a fraction from two subexpressions - implementation
57 : //
58 :
59 : // various fraction line thicknesses (multiplicative values of the default rule thickness)
60 :
61 : #define THIN_FRACTION_LINE 0.5f
62 : #define THIN_FRACTION_LINE_MINIMUM_PIXELS 1 // minimum of 1 pixel
63 :
64 : #define THICK_FRACTION_LINE 2.0f
65 : #define THICK_FRACTION_LINE_MINIMUM_PIXELS 2 // minimum of 2 pixels
66 :
67 : nsIFrame*
68 0 : NS_NewMathMLmfracFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
69 : {
70 0 : return new (aPresShell) nsMathMLmfracFrame(aContext);
71 : }
72 :
73 0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfracFrame)
74 :
75 0 : nsMathMLmfracFrame::~nsMathMLmfracFrame()
76 : {
77 0 : }
78 :
79 : eMathMLFrameType
80 0 : nsMathMLmfracFrame::GetMathMLFrameType()
81 : {
82 : // frac is "inner" in TeXBook, Appendix G, rule 15e. See also page 170.
83 0 : return eMathMLFrameType_Inner;
84 : }
85 :
86 : NS_IMETHODIMP
87 0 : nsMathMLmfracFrame::TransmitAutomaticData()
88 : {
89 : // 1. The REC says:
90 : // The <mfrac> element sets displaystyle to "false", or if it was already
91 : // false increments scriptlevel by 1, within numerator and denominator.
92 : // 2. The TeXbook (Ch 17. p.141) says the numerator inherits the compression
93 : // while the denominator is compressed
94 0 : bool increment = !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags);
95 0 : SetIncrementScriptLevel(0, increment);
96 0 : SetIncrementScriptLevel(1, increment);
97 :
98 : UpdatePresentationDataFromChildAt(0, -1,
99 : ~NS_MATHML_DISPLAYSTYLE,
100 0 : NS_MATHML_DISPLAYSTYLE);
101 : UpdatePresentationDataFromChildAt(1, 1,
102 : NS_MATHML_COMPRESSED,
103 0 : NS_MATHML_COMPRESSED);
104 :
105 : // if our numerator is an embellished operator, let its state bubble to us
106 0 : GetEmbellishDataFrom(mFrames.FirstChild(), mEmbellishData);
107 0 : if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) {
108 : // even when embellished, we need to record that <mfrac> won't fire
109 : // Stretch() on its embellished child
110 0 : mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
111 : }
112 :
113 0 : return NS_OK;
114 : }
115 :
116 : nscoord
117 0 : nsMathMLmfracFrame::CalcLineThickness(nsPresContext* aPresContext,
118 : nsStyleContext* aStyleContext,
119 : nsString& aThicknessAttribute,
120 : nscoord onePixel,
121 : nscoord aDefaultRuleThickness)
122 : {
123 0 : nscoord defaultThickness = aDefaultRuleThickness;
124 0 : nscoord lineThickness = aDefaultRuleThickness;
125 0 : nscoord minimumThickness = onePixel;
126 :
127 0 : if (!aThicknessAttribute.IsEmpty()) {
128 0 : if (aThicknessAttribute.EqualsLiteral("thin")) {
129 0 : lineThickness = NSToCoordFloor(defaultThickness * THIN_FRACTION_LINE);
130 0 : minimumThickness = onePixel * THIN_FRACTION_LINE_MINIMUM_PIXELS;
131 : // should visually decrease by at least one pixel, if default is not a pixel
132 0 : if (defaultThickness > onePixel && lineThickness > defaultThickness - onePixel)
133 0 : lineThickness = defaultThickness - onePixel;
134 : }
135 0 : else if (aThicknessAttribute.EqualsLiteral("medium")) {
136 : // medium is default
137 : }
138 0 : else if (aThicknessAttribute.EqualsLiteral("thick")) {
139 0 : lineThickness = NSToCoordCeil(defaultThickness * THICK_FRACTION_LINE);
140 0 : minimumThickness = onePixel * THICK_FRACTION_LINE_MINIMUM_PIXELS;
141 : // should visually increase by at least one pixel
142 0 : if (lineThickness < defaultThickness + onePixel)
143 0 : lineThickness = defaultThickness + onePixel;
144 : }
145 : else { // see if it is a plain number, or a percentage, or a h/v-unit like 1ex, 2px, 1em
146 0 : nsCSSValue cssValue;
147 0 : if (ParseNumericValue(aThicknessAttribute, cssValue)) {
148 0 : nsCSSUnit unit = cssValue.GetUnit();
149 0 : if (eCSSUnit_Number == unit)
150 0 : lineThickness = nscoord(float(defaultThickness) * cssValue.GetFloatValue());
151 0 : else if (eCSSUnit_Percent == unit)
152 0 : lineThickness = nscoord(float(defaultThickness) * cssValue.GetPercentValue());
153 0 : else if (eCSSUnit_Null != unit)
154 0 : lineThickness = CalcLength(aPresContext, aStyleContext, cssValue);
155 : }
156 : }
157 : }
158 :
159 : // use minimum if the lineThickness is a non-zero value less than minimun
160 0 : if (lineThickness && lineThickness < minimumThickness)
161 0 : lineThickness = minimumThickness;
162 :
163 0 : return lineThickness;
164 : }
165 :
166 : NS_IMETHODIMP
167 0 : nsMathMLmfracFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
168 : const nsRect& aDirtyRect,
169 : const nsDisplayListSet& aLists)
170 : {
171 : /////////////
172 : // paint the numerator and denominator
173 0 : nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
174 0 : NS_ENSURE_SUCCESS(rv, rv);
175 :
176 : /////////////
177 : // paint the fraction line
178 0 : if (mIsBevelled) {
179 0 : rv = DisplaySlash(aBuilder, this, mLineRect, mLineThickness, aLists);
180 : } else {
181 0 : rv = DisplayBar(aBuilder, this, mLineRect, aLists);
182 : }
183 :
184 0 : return rv;
185 : }
186 :
187 : /* virtual */ nsresult
188 0 : nsMathMLmfracFrame::MeasureForWidth(nsRenderingContext& aRenderingContext,
189 : nsHTMLReflowMetrics& aDesiredSize)
190 : {
191 : return PlaceInternal(aRenderingContext,
192 : false,
193 : aDesiredSize,
194 0 : true);
195 : }
196 :
197 : nscoord
198 0 : nsMathMLmfracFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
199 : {
200 0 : nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
201 0 : if (!gap) return 0;
202 :
203 0 : mLineRect.MoveBy(gap, 0);
204 0 : return gap;
205 : }
206 :
207 : /* virtual */ nsresult
208 0 : nsMathMLmfracFrame::Place(nsRenderingContext& aRenderingContext,
209 : bool aPlaceOrigin,
210 : nsHTMLReflowMetrics& aDesiredSize)
211 : {
212 : return PlaceInternal(aRenderingContext,
213 : aPlaceOrigin,
214 : aDesiredSize,
215 0 : false);
216 : }
217 :
218 : nsresult
219 0 : nsMathMLmfracFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
220 : bool aPlaceOrigin,
221 : nsHTMLReflowMetrics& aDesiredSize,
222 : bool aWidthOnly)
223 : {
224 : ////////////////////////////////////
225 : // Get the children's desired sizes
226 0 : nsBoundingMetrics bmNum, bmDen;
227 0 : nsHTMLReflowMetrics sizeNum;
228 0 : nsHTMLReflowMetrics sizeDen;
229 0 : nsIFrame* frameDen = nsnull;
230 0 : nsIFrame* frameNum = mFrames.FirstChild();
231 0 : if (frameNum)
232 0 : frameDen = frameNum->GetNextSibling();
233 0 : if (!frameNum || !frameDen || frameDen->GetNextSibling()) {
234 : // report an error, encourage people to get their markups in order
235 0 : return ReflowError(aRenderingContext, aDesiredSize);
236 : }
237 0 : GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum);
238 0 : GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen);
239 :
240 0 : nsPresContext* presContext = PresContext();
241 0 : nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
242 :
243 0 : nsRefPtr<nsFontMetrics> fm;
244 0 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
245 0 : aRenderingContext.SetFont(fm);
246 :
247 : nscoord defaultRuleThickness, axisHeight;
248 0 : GetRuleThickness(aRenderingContext, fm, defaultRuleThickness);
249 0 : GetAxisHeight(aRenderingContext, fm, axisHeight);
250 :
251 0 : nsEmbellishData coreData;
252 0 : GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
253 :
254 : // see if the linethickness attribute is there
255 0 : nsAutoString value;
256 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::linethickness_,
257 0 : value);
258 :
259 : mLineThickness = CalcLineThickness(presContext, mStyleContext, value,
260 0 : onePixel, defaultRuleThickness);
261 :
262 : // bevelled attribute
263 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::bevelled_,
264 0 : value);
265 0 : mIsBevelled = value.EqualsLiteral("true");
266 :
267 0 : if (!mIsBevelled) {
268 0 : mLineRect.height = mLineThickness;
269 :
270 : // by default, leave at least one-pixel padding at either end, or use
271 : // lspace & rspace that may come from <mo> if we are an embellished
272 : // container (we fetch values from the core since they may use units that
273 : // depend on style data, and style changes could have occurred in the
274 : // core since our last visit there)
275 : nscoord leftSpace = NS_MAX(onePixel,
276 : NS_MATHML_IS_RTL(mPresentationData.flags) ?
277 0 : coreData.trailingSpace : coreData.leadingSpace);
278 : nscoord rightSpace = NS_MAX(onePixel,
279 : NS_MATHML_IS_RTL(mPresentationData.flags) ?
280 0 : coreData.leadingSpace : coreData.trailingSpace);
281 :
282 : //////////////////
283 : // Get shifts
284 0 : nscoord numShift = 0;
285 0 : nscoord denShift = 0;
286 :
287 : // Rule 15b, App. G, TeXbook
288 : nscoord numShift1, numShift2, numShift3;
289 : nscoord denShift1, denShift2;
290 :
291 0 : GetNumeratorShifts(fm, numShift1, numShift2, numShift3);
292 0 : GetDenominatorShifts(fm, denShift1, denShift2);
293 0 : if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
294 : // C > T
295 0 : numShift = numShift1;
296 0 : denShift = denShift1;
297 : }
298 : else {
299 0 : numShift = (0 < mLineRect.height) ? numShift2 : numShift3;
300 0 : denShift = denShift2;
301 : }
302 :
303 0 : nscoord minClearance = 0;
304 0 : nscoord actualClearance = 0;
305 :
306 0 : nscoord actualRuleThickness = mLineThickness;
307 :
308 0 : if (0 == actualRuleThickness) {
309 : // Rule 15c, App. G, TeXbook
310 :
311 : // min clearance between numerator and denominator
312 : minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ?
313 0 : 7 * defaultRuleThickness : 3 * defaultRuleThickness;
314 : actualClearance =
315 0 : (numShift - bmNum.descent) - (bmDen.ascent - denShift);
316 : // actualClearance should be >= minClearance
317 0 : if (actualClearance < minClearance) {
318 0 : nscoord halfGap = (minClearance - actualClearance)/2;
319 0 : numShift += halfGap;
320 0 : denShift += halfGap;
321 : }
322 : }
323 : else {
324 : // Rule 15d, App. G, TeXbook
325 :
326 : // min clearance between numerator or denominator and middle of bar
327 :
328 : // TeX has a different interpretation of the thickness.
329 : // Try $a \above10pt b$ to see. Here is what TeX does:
330 : // minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ?
331 : // 3 * actualRuleThickness : actualRuleThickness;
332 :
333 : // we slightly depart from TeX here. We use the defaultRuleThickness instead
334 : // of the value coming from the linethickness attribute, i.e., we recover what
335 : // TeX does if the user hasn't set linethickness. But when the linethickness
336 : // is set, we avoid the wide gap problem.
337 : minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ?
338 0 : 3 * defaultRuleThickness : defaultRuleThickness + onePixel;
339 :
340 : // adjust numShift to maintain minClearance if needed
341 : actualClearance =
342 0 : (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2);
343 0 : if (actualClearance < minClearance) {
344 0 : numShift += (minClearance - actualClearance);
345 : }
346 : // adjust denShift to maintain minClearance if needed
347 : actualClearance =
348 0 : (axisHeight - actualRuleThickness/2) - (bmDen.ascent - denShift);
349 0 : if (actualClearance < minClearance) {
350 0 : denShift += (minClearance - actualClearance);
351 : }
352 : }
353 :
354 : //////////////////
355 : // Place Children
356 :
357 : // XXX Need revisiting the width. TeX uses the exact width
358 : // e.g. in $$\huge\frac{\displaystyle\int}{i}$$
359 0 : nscoord width = NS_MAX(bmNum.width, bmDen.width);
360 0 : nscoord dxNum = leftSpace + (width - sizeNum.width)/2;
361 0 : nscoord dxDen = leftSpace + (width - sizeDen.width)/2;
362 0 : width += leftSpace + rightSpace;
363 :
364 : // see if the numalign attribute is there
365 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::numalign_,
366 0 : value);
367 0 : if (value.EqualsLiteral("left"))
368 0 : dxNum = leftSpace;
369 0 : else if (value.EqualsLiteral("right"))
370 0 : dxNum = width - rightSpace - sizeNum.width;
371 :
372 : // see if the denomalign attribute is there
373 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::denomalign_,
374 0 : value);
375 0 : if (value.EqualsLiteral("left"))
376 0 : dxDen = leftSpace;
377 0 : else if (value.EqualsLiteral("right"))
378 0 : dxDen = width - rightSpace - sizeDen.width;
379 :
380 : mBoundingMetrics.rightBearing =
381 0 : NS_MAX(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing);
382 0 : if (mBoundingMetrics.rightBearing < width - rightSpace)
383 0 : mBoundingMetrics.rightBearing = width - rightSpace;
384 : mBoundingMetrics.leftBearing =
385 0 : NS_MIN(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing);
386 0 : if (mBoundingMetrics.leftBearing > leftSpace)
387 0 : mBoundingMetrics.leftBearing = leftSpace;
388 0 : mBoundingMetrics.ascent = bmNum.ascent + numShift;
389 0 : mBoundingMetrics.descent = bmDen.descent + denShift;
390 0 : mBoundingMetrics.width = width;
391 :
392 0 : aDesiredSize.ascent = sizeNum.ascent + numShift;
393 : aDesiredSize.height = aDesiredSize.ascent +
394 0 : sizeDen.height - sizeDen.ascent + denShift;
395 0 : aDesiredSize.width = mBoundingMetrics.width;
396 0 : aDesiredSize.mBoundingMetrics = mBoundingMetrics;
397 :
398 0 : mReference.x = 0;
399 0 : mReference.y = aDesiredSize.ascent;
400 :
401 0 : if (aPlaceOrigin) {
402 : nscoord dy;
403 : // place numerator
404 0 : dy = 0;
405 0 : FinishReflowChild(frameNum, presContext, nsnull, sizeNum, dxNum, dy, 0);
406 : // place denominator
407 0 : dy = aDesiredSize.height - sizeDen.height;
408 0 : FinishReflowChild(frameDen, presContext, nsnull, sizeDen, dxDen, dy, 0);
409 : // place the fraction bar - dy is top of bar
410 0 : dy = aDesiredSize.ascent - (axisHeight + actualRuleThickness/2);
411 : mLineRect.SetRect(leftSpace, dy, width - (leftSpace + rightSpace),
412 0 : actualRuleThickness);
413 : }
414 : } else {
415 0 : nscoord numShift = 0.0;
416 0 : nscoord denShift = 0.0;
417 0 : nscoord padding = 3 * defaultRuleThickness;
418 0 : nscoord slashRatio = 3;
419 :
420 : // Define the constant used in the expression of the maximum width
421 0 : nscoord em = fm->EmHeight();
422 0 : nscoord slashMaxWidthConstant = 2 * em;
423 :
424 : // For large line thicknesses the minimum slash height is limited to the
425 : // largest expected height of a fraction
426 : nscoord slashMinHeight = slashRatio *
427 0 : NS_MIN(2 * mLineThickness, slashMaxWidthConstant);
428 :
429 0 : nscoord leadingSpace = NS_MAX(padding, coreData.leadingSpace);
430 0 : nscoord trailingSpace = NS_MAX(padding, coreData.trailingSpace);
431 : nscoord delta;
432 :
433 : // ___________
434 : // | | /
435 : // {|-NUMERATOR-| /
436 : // {|___________| S
437 : // { L
438 : // numShift{ A
439 : // ------------------------------------------------------- baseline
440 : // S _____________ } denShift
441 : // H | |}
442 : // / |-DENOMINATOR-|}
443 : // / |_____________|
444 : //
445 :
446 : // first, ensure that the top of the numerator is at least as high as the
447 : // top of the denominator (and the reverse for the bottoms)
448 : delta = NS_MAX(bmDen.ascent - bmNum.ascent,
449 0 : bmNum.descent - bmDen.descent) / 2;
450 0 : if (delta > 0) {
451 0 : numShift += delta;
452 0 : denShift += delta;
453 : }
454 :
455 0 : if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
456 : delta = NS_MIN(bmDen.ascent + bmDen.descent,
457 0 : bmNum.ascent + bmNum.descent) / 2;
458 0 : numShift += delta;
459 0 : denShift += delta;
460 : } else {
461 0 : nscoord xHeight = fm->XHeight();
462 0 : numShift += xHeight / 2;
463 0 : denShift += xHeight / 4;
464 : }
465 :
466 : // Set the ascent/descent of our BoundingMetrics.
467 0 : mBoundingMetrics.ascent = bmNum.ascent + numShift;
468 0 : mBoundingMetrics.descent = bmDen.descent + denShift;
469 :
470 : // At this point the height of the slash is
471 : // mBoundingMetrics.ascent + mBoundingMetrics.descent
472 : // Ensure that it is greater than slashMinHeight
473 : delta = (slashMinHeight -
474 0 : (mBoundingMetrics.ascent + mBoundingMetrics.descent)) / 2;
475 0 : if (delta > 0) {
476 0 : mBoundingMetrics.ascent += delta;
477 0 : mBoundingMetrics.descent += delta;
478 : }
479 :
480 : // Set the width of the slash
481 0 : if (aWidthOnly) {
482 0 : mLineRect.width = mLineThickness + slashMaxWidthConstant;
483 : } else {
484 : mLineRect.width = mLineThickness +
485 : NS_MIN(slashMaxWidthConstant,
486 : (mBoundingMetrics.ascent + mBoundingMetrics.descent) /
487 0 : slashRatio);
488 : }
489 :
490 : // Set horizontal bounding metrics
491 0 : if (NS_MATHML_IS_RTL(mPresentationData.flags)) {
492 0 : mBoundingMetrics.leftBearing = trailingSpace + bmDen.leftBearing;
493 0 : mBoundingMetrics.rightBearing = trailingSpace + bmDen.width + mLineRect.width + bmNum.rightBearing;
494 : } else {
495 0 : mBoundingMetrics.leftBearing = leadingSpace + bmNum.leftBearing;
496 0 : mBoundingMetrics.rightBearing = leadingSpace + bmNum.width + mLineRect.width + bmDen.rightBearing;
497 : }
498 : mBoundingMetrics.width =
499 : leadingSpace + bmNum.width + mLineRect.width + bmDen.width +
500 0 : trailingSpace;
501 :
502 : // Set aDesiredSize
503 0 : aDesiredSize.ascent = mBoundingMetrics.ascent + padding;
504 : aDesiredSize.height =
505 0 : mBoundingMetrics.ascent + mBoundingMetrics.descent + 2 * padding;
506 0 : aDesiredSize.width = mBoundingMetrics.width;
507 0 : aDesiredSize.mBoundingMetrics = mBoundingMetrics;
508 :
509 0 : mReference.x = 0;
510 0 : mReference.y = aDesiredSize.ascent;
511 :
512 0 : if (aPlaceOrigin) {
513 : nscoord dx, dy;
514 :
515 : // place numerator
516 : dx = MirrorIfRTL(aDesiredSize.width, sizeNum.width,
517 0 : leadingSpace);
518 0 : dy = aDesiredSize.ascent - numShift - sizeNum.ascent;
519 0 : FinishReflowChild(frameNum, presContext, nsnull, sizeNum, dx, dy, 0);
520 :
521 : // place the fraction bar
522 : dx = MirrorIfRTL(aDesiredSize.width, mLineRect.width,
523 0 : leadingSpace + bmNum.width);
524 0 : dy = aDesiredSize.ascent - mBoundingMetrics.ascent;
525 : mLineRect.SetRect(dx, dy,
526 0 : mLineRect.width, aDesiredSize.height - 2 * padding);
527 :
528 : // place denominator
529 : dx = MirrorIfRTL(aDesiredSize.width, sizeDen.width,
530 0 : leadingSpace + bmNum.width + mLineRect.width);
531 0 : dy = aDesiredSize.ascent + denShift - sizeDen.ascent;
532 0 : FinishReflowChild(frameDen, presContext, nsnull, sizeDen, dx, dy, 0);
533 : }
534 :
535 : }
536 :
537 0 : return NS_OK;
538 : }
539 :
540 : NS_IMETHODIMP
541 0 : nsMathMLmfracFrame::UpdatePresentationDataFromChildAt(PRInt32 aFirstIndex,
542 : PRInt32 aLastIndex,
543 : PRUint32 aFlagsValues,
544 : PRUint32 aFlagsToUpdate)
545 : {
546 : // The REC says "The <mfrac> element sets displaystyle to "false" within
547 : // numerator and denominator"
548 : #if 0
549 : // At one point I thought that it meant that the displaystyle state of
550 : // the numerator and denominator cannot be modified by an ancestor, i.e.,
551 : // to change the displaystyle, one has to use displaystyle="true" with mstyle:
552 : // <mfrac> <mstyle>numerator</mstyle> <mstyle>denominator</mstyle> </mfrac>
553 :
554 : // Commenting out for now until it is clear what the intention really is.
555 : // See also the variants for <mover>, <munder>, <munderover>
556 :
557 : aFlagsToUpdate &= ~NS_MATHML_DISPLAYSTYLE;
558 : aFlagsValues &= ~NS_MATHML_DISPLAYSTYLE;
559 : #endif
560 : return nsMathMLContainerFrame::
561 : UpdatePresentationDataFromChildAt(aFirstIndex, aLastIndex,
562 0 : aFlagsValues, aFlagsToUpdate);
563 : }
564 :
565 : class nsDisplayMathMLSlash : public nsDisplayItem {
566 : public:
567 0 : nsDisplayMathMLSlash(nsDisplayListBuilder* aBuilder,
568 : nsIFrame* aFrame, const nsRect& aRect,
569 : nscoord aThickness, bool aRTL)
570 : : nsDisplayItem(aBuilder, aFrame), mRect(aRect), mThickness(aThickness),
571 0 : mRTL(aRTL) {
572 0 : MOZ_COUNT_CTOR(nsDisplayMathMLSlash);
573 0 : }
574 : #ifdef NS_BUILD_REFCNT_LOGGING
575 0 : virtual ~nsDisplayMathMLSlash() {
576 0 : MOZ_COUNT_DTOR(nsDisplayMathMLSlash);
577 0 : }
578 : #endif
579 :
580 : virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
581 0 : NS_DISPLAY_DECL_NAME("MathMLSlash", TYPE_MATHML_SLASH)
582 :
583 : private:
584 : nsRect mRect;
585 : nscoord mThickness;
586 : bool mRTL;
587 : };
588 :
589 0 : void nsDisplayMathMLSlash::Paint(nsDisplayListBuilder* aBuilder,
590 : nsRenderingContext* aCtx)
591 : {
592 : // get the gfxRect
593 0 : nsPresContext* presContext = mFrame->PresContext();
594 0 : gfxRect rect = presContext->AppUnitsToGfxUnits(mRect + ToReferenceFrame());
595 :
596 : // paint with the current text color
597 0 : aCtx->SetColor(mFrame->GetVisitedDependentColor(eCSSProperty_color));
598 :
599 : // draw the slash as a parallelogram
600 0 : gfxContext *gfxCtx = aCtx->ThebesContext();
601 0 : gfxPoint delta = gfxPoint(presContext->AppUnitsToGfxUnits(mThickness), 0);
602 0 : gfxCtx->NewPath();
603 :
604 0 : if (mRTL) {
605 0 : gfxCtx->MoveTo(rect.TopLeft());
606 0 : gfxCtx->LineTo(rect.TopLeft() + delta);
607 0 : gfxCtx->LineTo(rect.BottomRight());
608 0 : gfxCtx->LineTo(rect.BottomRight() - delta);
609 : } else {
610 0 : gfxCtx->MoveTo(rect.BottomLeft());
611 0 : gfxCtx->LineTo(rect.BottomLeft() + delta);
612 0 : gfxCtx->LineTo(rect.TopRight());
613 0 : gfxCtx->LineTo(rect.TopRight() - delta);
614 : }
615 :
616 0 : gfxCtx->ClosePath();
617 0 : gfxCtx->Fill();
618 0 : }
619 :
620 : nsresult
621 0 : nsMathMLmfracFrame::DisplaySlash(nsDisplayListBuilder* aBuilder,
622 : nsIFrame* aFrame, const nsRect& aRect,
623 : nscoord aThickness,
624 : const nsDisplayListSet& aLists) {
625 0 : if (!aFrame->GetStyleVisibility()->IsVisible() || aRect.IsEmpty())
626 0 : return NS_OK;
627 :
628 : return aLists.Content()->AppendNewToTop(new (aBuilder)
629 : nsDisplayMathMLSlash(aBuilder, aFrame, aRect, aThickness,
630 0 : NS_MATHML_IS_RTL(mPresentationData.flags)));
631 : }
|