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