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 : * Vilya Harvey <vilya@nag.co.uk>
26 : * Shyjan Mahamud <mahamud@cs.cmu.edu>
27 : * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
28 : * Frederic Wang <fred.wang@free.fr> - extension of <msqrt/> to <menclose/>
29 : *
30 : * Alternatively, the contents of this file may be used under the terms of
31 : * either of the GNU General Public License Version 2 or later (the "GPL"),
32 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 : * in which case the provisions of the GPL or the LGPL are applicable instead
34 : * of those above. If you wish to allow use of your version of this file only
35 : * under the terms of either the GPL or the LGPL, and not to allow others to
36 : * use your version of this file under the terms of the MPL, indicate your
37 : * decision by deleting the provisions above and replace them with the notice
38 : * and other provisions required by the GPL or the LGPL. If you do not delete
39 : * the provisions above, a recipient may use your version of this file under
40 : * the terms of any one of the MPL, the GPL or the LGPL.
41 : *
42 : * ***** END LICENSE BLOCK ***** */
43 :
44 :
45 : #include "nsCOMPtr.h"
46 : #include "nsFrame.h"
47 : #include "nsPresContext.h"
48 : #include "nsStyleContext.h"
49 : #include "nsStyleConsts.h"
50 : #include "nsRenderingContext.h"
51 : #include "nsWhitespaceTokenizer.h"
52 :
53 : #include "nsMathMLmencloseFrame.h"
54 : #include "nsDisplayList.h"
55 : #include "gfxContext.h"
56 :
57 : //
58 : // <menclose> -- enclose content with a stretching symbol such
59 : // as a long division sign. - implementation
60 :
61 : // longdiv:
62 : // Unicode 5.1 assigns U+27CC to LONG DIVISION, but a right parenthesis
63 : // renders better with current font support.
64 : static const PRUnichar kLongDivChar = ')';
65 :
66 : // radical: 'SQUARE ROOT'
67 : static const PRUnichar kRadicalChar = 0x221A;
68 :
69 : nsIFrame*
70 0 : NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
71 : {
72 0 : return new (aPresShell) nsMathMLmencloseFrame(aContext);
73 : }
74 :
75 0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmencloseFrame)
76 :
77 0 : nsMathMLmencloseFrame::nsMathMLmencloseFrame(nsStyleContext* aContext) :
78 : nsMathMLContainerFrame(aContext), mNotationsToDraw(0),
79 0 : mLongDivCharIndex(-1), mRadicalCharIndex(-1), mContentWidth(0)
80 : {
81 0 : }
82 :
83 0 : nsMathMLmencloseFrame::~nsMathMLmencloseFrame()
84 : {
85 0 : }
86 :
87 0 : nsresult nsMathMLmencloseFrame::AllocateMathMLChar(nsMencloseNotation mask)
88 : {
89 : // Is the char already allocated?
90 0 : if ((mask == NOTATION_LONGDIV && mLongDivCharIndex >= 0) ||
91 : (mask == NOTATION_RADICAL && mRadicalCharIndex >= 0))
92 0 : return NS_OK;
93 :
94 : // No need to track the style context given to our MathML chars.
95 : // The Style System will use Get/SetAdditionalStyleContext() to keep it
96 : // up-to-date if dynamic changes arise.
97 0 : PRUint32 i = mMathMLChar.Length();
98 0 : nsAutoString Char;
99 :
100 0 : if (!mMathMLChar.AppendElement())
101 0 : return NS_ERROR_OUT_OF_MEMORY;
102 :
103 0 : if (mask == NOTATION_LONGDIV) {
104 0 : Char.Assign(kLongDivChar);
105 0 : mLongDivCharIndex = i;
106 0 : } else if (mask == NOTATION_RADICAL) {
107 0 : Char.Assign(kRadicalChar);
108 0 : mRadicalCharIndex = i;
109 : }
110 :
111 0 : nsPresContext *presContext = PresContext();
112 0 : mMathMLChar[i].SetData(presContext, Char);
113 : ResolveMathMLCharStyle(presContext, mContent, mStyleContext,
114 0 : &mMathMLChar[i],
115 0 : true);
116 :
117 0 : return NS_OK;
118 : }
119 :
120 : /*
121 : * Add a notation to draw, if the argument is the name of a known notation.
122 : * @param aNotation string name of a notation
123 : */
124 0 : nsresult nsMathMLmencloseFrame::AddNotation(const nsAString& aNotation)
125 : {
126 : nsresult rv;
127 :
128 0 : if (aNotation.EqualsLiteral("longdiv")) {
129 0 : rv = AllocateMathMLChar(NOTATION_LONGDIV);
130 0 : NS_ENSURE_SUCCESS(rv, rv);
131 0 : mNotationsToDraw |= NOTATION_LONGDIV;
132 0 : } else if (aNotation.EqualsLiteral("actuarial")) {
133 0 : mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_TOP);
134 0 : } else if (aNotation.EqualsLiteral("radical")) {
135 0 : rv = AllocateMathMLChar(NOTATION_RADICAL);
136 0 : NS_ENSURE_SUCCESS(rv, rv);
137 0 : mNotationsToDraw |= NOTATION_RADICAL;
138 0 : } else if (aNotation.EqualsLiteral("box")) {
139 : mNotationsToDraw |= (NOTATION_LEFT | NOTATION_RIGHT |
140 0 : NOTATION_TOP | NOTATION_BOTTOM);
141 0 : } else if (aNotation.EqualsLiteral("roundedbox")) {
142 0 : mNotationsToDraw |= NOTATION_ROUNDEDBOX;
143 0 : } else if (aNotation.EqualsLiteral("circle")) {
144 0 : mNotationsToDraw |= NOTATION_CIRCLE;
145 0 : } else if (aNotation.EqualsLiteral("left")) {
146 0 : mNotationsToDraw |= NOTATION_LEFT;
147 0 : } else if (aNotation.EqualsLiteral("right")) {
148 0 : mNotationsToDraw |= NOTATION_RIGHT;
149 0 : } else if (aNotation.EqualsLiteral("top")) {
150 0 : mNotationsToDraw |= NOTATION_TOP;
151 0 : } else if (aNotation.EqualsLiteral("bottom")) {
152 0 : mNotationsToDraw |= NOTATION_BOTTOM;
153 0 : } else if (aNotation.EqualsLiteral("updiagonalstrike")) {
154 0 : mNotationsToDraw |= NOTATION_UPDIAGONALSTRIKE;
155 0 : } else if (aNotation.EqualsLiteral("downdiagonalstrike")) {
156 0 : mNotationsToDraw |= NOTATION_DOWNDIAGONALSTRIKE;
157 0 : } else if (aNotation.EqualsLiteral("verticalstrike")) {
158 0 : mNotationsToDraw |= NOTATION_VERTICALSTRIKE;
159 0 : } else if (aNotation.EqualsLiteral("horizontalstrike")) {
160 0 : mNotationsToDraw |= NOTATION_HORIZONTALSTRIKE;
161 0 : } else if (aNotation.EqualsLiteral("madruwb")) {
162 0 : mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_BOTTOM);
163 : }
164 :
165 0 : return NS_OK;
166 : }
167 :
168 : /*
169 : * Initialize the list of notations to draw
170 : */
171 0 : void nsMathMLmencloseFrame::InitNotations()
172 : {
173 0 : mNotationsToDraw = 0;
174 0 : mLongDivCharIndex = mRadicalCharIndex = -1;
175 0 : mMathMLChar.Clear();
176 :
177 0 : nsAutoString value;
178 :
179 0 : if (GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::notation_,
180 0 : value)) {
181 : // parse the notation attribute
182 0 : nsWhitespaceTokenizer tokenizer(value);
183 :
184 0 : while (tokenizer.hasMoreTokens())
185 0 : AddNotation(tokenizer.nextToken());
186 : } else {
187 : // default: longdiv
188 0 : if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV)))
189 : return;
190 0 : mNotationsToDraw = NOTATION_LONGDIV;
191 : }
192 : }
193 :
194 : NS_IMETHODIMP
195 0 : nsMathMLmencloseFrame::InheritAutomaticData(nsIFrame* aParent)
196 : {
197 : // let the base class get the default from our parent
198 0 : nsMathMLContainerFrame::InheritAutomaticData(aParent);
199 :
200 0 : mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
201 :
202 0 : InitNotations();
203 :
204 0 : return NS_OK;
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsMathMLmencloseFrame::TransmitAutomaticData()
209 : {
210 0 : if (IsToDraw(NOTATION_RADICAL)) {
211 : // The TeXBook (Ch 17. p.141) says that \sqrt is cramped
212 : UpdatePresentationDataFromChildAt(0, -1,
213 : NS_MATHML_COMPRESSED,
214 0 : NS_MATHML_COMPRESSED);
215 : }
216 :
217 0 : return NS_OK;
218 : }
219 :
220 : NS_IMETHODIMP
221 0 : nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
222 : const nsRect& aDirtyRect,
223 : const nsDisplayListSet& aLists)
224 : {
225 : /////////////
226 : // paint the menclosed content
227 : nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect,
228 0 : aLists);
229 :
230 0 : NS_ENSURE_SUCCESS(rv, rv);
231 :
232 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags))
233 0 : return rv;
234 :
235 0 : nsRect mencloseRect = nsIFrame::GetRect();
236 0 : mencloseRect.x = mencloseRect.y = 0;
237 :
238 0 : if (IsToDraw(NOTATION_RADICAL)) {
239 0 : rv = mMathMLChar[mRadicalCharIndex].Display(aBuilder, this, aLists);
240 0 : NS_ENSURE_SUCCESS(rv, rv);
241 :
242 0 : nsRect rect;
243 0 : mMathMLChar[mRadicalCharIndex].GetRect(rect);
244 : rect.MoveBy(NS_MATHML_IS_RTL(mPresentationData.flags) ?
245 0 : -mContentWidth : rect.width, 0);
246 0 : rect.SizeTo(mContentWidth, mRuleThickness);
247 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
248 0 : NS_ENSURE_SUCCESS(rv, rv);
249 : }
250 :
251 0 : if (IsToDraw(NOTATION_LONGDIV)) {
252 0 : rv = mMathMLChar[mLongDivCharIndex].Display(aBuilder, this, aLists);
253 0 : NS_ENSURE_SUCCESS(rv, rv);
254 :
255 0 : nsRect rect;
256 0 : mMathMLChar[mLongDivCharIndex].GetRect(rect);
257 0 : rect.SizeTo(rect.width + mContentWidth, mRuleThickness);
258 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
259 0 : NS_ENSURE_SUCCESS(rv, rv);
260 : }
261 :
262 0 : if (IsToDraw(NOTATION_TOP)) {
263 0 : nsRect rect(0, 0, mencloseRect.width, mRuleThickness);
264 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
265 0 : NS_ENSURE_SUCCESS(rv, rv);
266 : }
267 :
268 0 : if (IsToDraw(NOTATION_BOTTOM)) {
269 : nsRect rect(0, mencloseRect.height - mRuleThickness,
270 0 : mencloseRect.width, mRuleThickness);
271 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
272 0 : NS_ENSURE_SUCCESS(rv, rv);
273 : }
274 :
275 0 : if (IsToDraw(NOTATION_LEFT)) {
276 0 : nsRect rect(0, 0, mRuleThickness, mencloseRect.height);
277 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
278 0 : NS_ENSURE_SUCCESS(rv, rv);
279 : }
280 :
281 0 : if (IsToDraw(NOTATION_RIGHT)) {
282 : nsRect rect(mencloseRect.width - mRuleThickness, 0,
283 0 : mRuleThickness, mencloseRect.height);
284 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
285 0 : NS_ENSURE_SUCCESS(rv, rv);
286 : }
287 :
288 0 : if (IsToDraw(NOTATION_ROUNDEDBOX)) {
289 : rv = DisplayNotation(aBuilder, this, mencloseRect, aLists,
290 0 : mRuleThickness, NOTATION_ROUNDEDBOX);
291 0 : NS_ENSURE_SUCCESS(rv, rv);
292 : }
293 :
294 0 : if (IsToDraw(NOTATION_CIRCLE)) {
295 : rv = DisplayNotation(aBuilder, this, mencloseRect, aLists,
296 0 : mRuleThickness, NOTATION_CIRCLE);
297 0 : NS_ENSURE_SUCCESS(rv, rv);
298 : }
299 :
300 0 : if (IsToDraw(NOTATION_UPDIAGONALSTRIKE)) {
301 : rv = DisplayNotation(aBuilder, this, mencloseRect, aLists,
302 0 : mRuleThickness, NOTATION_UPDIAGONALSTRIKE);
303 0 : NS_ENSURE_SUCCESS(rv, rv);
304 : }
305 :
306 0 : if (IsToDraw(NOTATION_DOWNDIAGONALSTRIKE)) {
307 : rv = DisplayNotation(aBuilder, this, mencloseRect, aLists,
308 0 : mRuleThickness, NOTATION_DOWNDIAGONALSTRIKE);
309 0 : NS_ENSURE_SUCCESS(rv, rv);
310 : }
311 :
312 0 : if (IsToDraw(NOTATION_HORIZONTALSTRIKE)) {
313 : nsRect rect(0, mencloseRect.height / 2 - mRuleThickness / 2,
314 0 : mencloseRect.width, mRuleThickness);
315 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
316 0 : NS_ENSURE_SUCCESS(rv, rv);
317 : }
318 :
319 0 : if (IsToDraw(NOTATION_VERTICALSTRIKE)) {
320 : nsRect rect(mencloseRect.width / 2 - mRuleThickness / 2, 0,
321 0 : mRuleThickness, mencloseRect.height);
322 0 : rv = DisplayBar(aBuilder, this, rect, aLists);
323 0 : NS_ENSURE_SUCCESS(rv, rv);
324 : }
325 0 : return rv;
326 : }
327 :
328 : /* virtual */ nsresult
329 0 : nsMathMLmencloseFrame::MeasureForWidth(nsRenderingContext& aRenderingContext,
330 : nsHTMLReflowMetrics& aDesiredSize)
331 : {
332 0 : return PlaceInternal(aRenderingContext, false, aDesiredSize, true);
333 : }
334 :
335 : /* virtual */ nsresult
336 0 : nsMathMLmencloseFrame::Place(nsRenderingContext& aRenderingContext,
337 : bool aPlaceOrigin,
338 : nsHTMLReflowMetrics& aDesiredSize)
339 : {
340 0 : return PlaceInternal(aRenderingContext, aPlaceOrigin, aDesiredSize, false);
341 : }
342 :
343 : /* virtual */ nsresult
344 0 : nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
345 : bool aPlaceOrigin,
346 : nsHTMLReflowMetrics& aDesiredSize,
347 : bool aWidthOnly)
348 : {
349 : ///////////////
350 : // Measure the size of our content using the base class to format like an
351 : // inferred mrow.
352 0 : nsHTMLReflowMetrics baseSize;
353 : nsresult rv =
354 0 : nsMathMLContainerFrame::Place(aRenderingContext, false, baseSize);
355 :
356 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
357 0 : DidReflowChildren(GetFirstPrincipalChild());
358 0 : return rv;
359 : }
360 :
361 0 : nsBoundingMetrics bmBase = baseSize.mBoundingMetrics;
362 0 : nscoord dx_left = 0, dx_right = 0;
363 0 : nsBoundingMetrics bmLongdivChar, bmRadicalChar;
364 0 : nscoord radicalAscent = 0, radicalDescent = 0;
365 0 : nscoord longdivAscent = 0, longdivDescent = 0;
366 0 : nscoord psi = 0;
367 :
368 : ///////////////
369 : // Thickness of bars and font metrics
370 0 : nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
371 :
372 : nscoord mEmHeight;
373 0 : nsRefPtr<nsFontMetrics> fm;
374 0 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
375 0 : aRenderingContext.SetFont(fm);
376 0 : GetRuleThickness(aRenderingContext, fm, mRuleThickness);
377 0 : GetEmHeight(fm, mEmHeight);
378 :
379 0 : PRUnichar one = '1';
380 0 : nsBoundingMetrics bmOne = aRenderingContext.GetBoundingMetrics(&one, 1);
381 :
382 : ///////////////
383 : // General rules: the menclose element takes the size of the enclosed content.
384 : // We add a padding when needed.
385 :
386 : // determine padding & psi
387 0 : nscoord padding = 3 * mRuleThickness;
388 0 : nscoord delta = padding % onePixel;
389 0 : if (delta)
390 0 : padding += onePixel - delta; // round up
391 :
392 0 : if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
393 : nscoord phi;
394 : // Rule 11, App. G, TeXbook
395 : // psi = clearance between rule and content
396 0 : if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags))
397 0 : phi = fm->XHeight();
398 : else
399 0 : phi = mRuleThickness;
400 0 : psi = mRuleThickness + phi / 4;
401 :
402 0 : delta = psi % onePixel;
403 0 : if (delta)
404 0 : psi += onePixel - delta; // round up
405 : }
406 :
407 0 : if (mRuleThickness < onePixel)
408 0 : mRuleThickness = onePixel;
409 :
410 : // Set horizontal parameters
411 0 : if (IsToDraw(NOTATION_ROUNDEDBOX) ||
412 0 : IsToDraw(NOTATION_TOP) ||
413 0 : IsToDraw(NOTATION_LEFT) ||
414 0 : IsToDraw(NOTATION_BOTTOM) ||
415 0 : IsToDraw(NOTATION_CIRCLE))
416 0 : dx_left = padding;
417 :
418 0 : if (IsToDraw(NOTATION_ROUNDEDBOX) ||
419 0 : IsToDraw(NOTATION_TOP) ||
420 0 : IsToDraw(NOTATION_RIGHT) ||
421 0 : IsToDraw(NOTATION_BOTTOM) ||
422 0 : IsToDraw(NOTATION_CIRCLE))
423 0 : dx_right = padding;
424 :
425 : // Set vertical parameters
426 0 : if (IsToDraw(NOTATION_RIGHT) ||
427 0 : IsToDraw(NOTATION_LEFT) ||
428 0 : IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
429 0 : IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
430 0 : IsToDraw(NOTATION_VERTICALSTRIKE) ||
431 0 : IsToDraw(NOTATION_CIRCLE) ||
432 0 : IsToDraw(NOTATION_ROUNDEDBOX) ||
433 0 : IsToDraw(NOTATION_RADICAL) ||
434 0 : IsToDraw(NOTATION_LONGDIV)) {
435 : // set a minimal value for the base height
436 0 : bmBase.ascent = NS_MAX(bmOne.ascent, bmBase.ascent);
437 0 : bmBase.descent = NS_MAX(0, bmBase.descent);
438 : }
439 :
440 0 : mBoundingMetrics.ascent = bmBase.ascent;
441 0 : mBoundingMetrics.descent = bmBase.descent;
442 :
443 0 : if (IsToDraw(NOTATION_ROUNDEDBOX) ||
444 0 : IsToDraw(NOTATION_TOP) ||
445 0 : IsToDraw(NOTATION_LEFT) ||
446 0 : IsToDraw(NOTATION_RIGHT) ||
447 0 : IsToDraw(NOTATION_CIRCLE))
448 0 : mBoundingMetrics.ascent += padding;
449 :
450 0 : if (IsToDraw(NOTATION_ROUNDEDBOX) ||
451 0 : IsToDraw(NOTATION_LEFT) ||
452 0 : IsToDraw(NOTATION_RIGHT) ||
453 0 : IsToDraw(NOTATION_BOTTOM) ||
454 0 : IsToDraw(NOTATION_CIRCLE))
455 0 : mBoundingMetrics.descent += padding;
456 :
457 : ///////////////
458 : // circle notation: we don't want the ellipse to overlap the enclosed
459 : // content. Hence, we need to increase the size of the bounding box by a
460 : // factor of at least sqrt(2).
461 0 : if (IsToDraw(NOTATION_CIRCLE)) {
462 0 : double ratio = (sqrt(2.0) - 1.0) / 2.0;
463 : nscoord padding2;
464 :
465 : // Update horizontal parameters
466 0 : padding2 = ratio * bmBase.width;
467 :
468 0 : dx_left = NS_MAX(dx_left, padding2);
469 0 : dx_right = NS_MAX(dx_right, padding2);
470 :
471 : // Update vertical parameters
472 0 : padding2 = ratio * (bmBase.ascent + bmBase.descent);
473 :
474 : mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent,
475 0 : bmBase.ascent + padding2);
476 : mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent,
477 0 : bmBase.descent + padding2);
478 : }
479 :
480 : ///////////////
481 : // longdiv notation:
482 0 : if (IsToDraw(NOTATION_LONGDIV)) {
483 0 : if (aWidthOnly) {
484 0 : nscoord longdiv_width = mMathMLChar[mLongDivCharIndex].
485 0 : GetMaxWidth(PresContext(), aRenderingContext);
486 :
487 : // Update horizontal parameters
488 0 : dx_left = NS_MAX(dx_left, longdiv_width);
489 : } else {
490 : // Stretch the parenthesis to the appropriate height if it is not
491 : // big enough.
492 0 : nsBoundingMetrics contSize = bmBase;
493 0 : contSize.ascent = mRuleThickness;
494 0 : contSize.descent = bmBase.ascent + bmBase.descent + psi;
495 :
496 : // height(longdiv) should be >= height(base) + psi + mRuleThickness
497 0 : mMathMLChar[mLongDivCharIndex].Stretch(PresContext(), aRenderingContext,
498 : NS_STRETCH_DIRECTION_VERTICAL,
499 : contSize, bmLongdivChar,
500 0 : NS_STRETCH_LARGER, false);
501 0 : mMathMLChar[mLongDivCharIndex].GetBoundingMetrics(bmLongdivChar);
502 :
503 : // Update horizontal parameters
504 0 : dx_left = NS_MAX(dx_left, bmLongdivChar.width);
505 :
506 : // Update vertical parameters
507 0 : longdivAscent = bmBase.ascent + psi + mRuleThickness;
508 : longdivDescent = NS_MAX(bmBase.descent,
509 : (bmLongdivChar.ascent + bmLongdivChar.descent -
510 0 : longdivAscent));
511 :
512 : mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent,
513 0 : longdivAscent);
514 : mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent,
515 0 : longdivDescent);
516 : }
517 : }
518 :
519 : ///////////////
520 : // radical notation:
521 0 : if (IsToDraw(NOTATION_RADICAL)) {
522 : nscoord *dx_leading =
523 0 : NS_MATHML_IS_RTL(mPresentationData.flags) ? &dx_right : &dx_left;
524 :
525 0 : if (aWidthOnly) {
526 0 : nscoord radical_width = mMathMLChar[mRadicalCharIndex].
527 0 : GetMaxWidth(PresContext(), aRenderingContext);
528 :
529 : // Update horizontal parameters
530 0 : *dx_leading = NS_MAX(*dx_leading, radical_width);
531 : } else {
532 : // Stretch the radical symbol to the appropriate height if it is not
533 : // big enough.
534 0 : nsBoundingMetrics contSize = bmBase;
535 0 : contSize.ascent = mRuleThickness;
536 0 : contSize.descent = bmBase.ascent + bmBase.descent + psi;
537 :
538 : // height(radical) should be >= height(base) + psi + mRuleThickness
539 0 : mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aRenderingContext,
540 : NS_STRETCH_DIRECTION_VERTICAL,
541 : contSize, bmRadicalChar,
542 : NS_STRETCH_LARGER,
543 0 : NS_MATHML_IS_RTL(mPresentationData.flags));
544 0 : mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar);
545 :
546 : // Update horizontal parameters
547 0 : *dx_leading = NS_MAX(*dx_leading, bmRadicalChar.width);
548 :
549 : // Update vertical parameters
550 0 : radicalAscent = bmBase.ascent + psi + mRuleThickness;
551 : radicalDescent = NS_MAX(bmBase.descent,
552 : (bmRadicalChar.ascent + bmRadicalChar.descent -
553 0 : radicalAscent));
554 :
555 : mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent,
556 0 : radicalAscent);
557 : mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent,
558 0 : radicalDescent);
559 : }
560 : }
561 :
562 : ///////////////
563 : //
564 0 : if (IsToDraw(NOTATION_CIRCLE) ||
565 0 : IsToDraw(NOTATION_ROUNDEDBOX) ||
566 0 : (IsToDraw(NOTATION_LEFT) && IsToDraw(NOTATION_RIGHT))) {
567 : // center the menclose around the content (horizontally)
568 0 : dx_left = dx_right = NS_MAX(dx_left, dx_right);
569 : }
570 :
571 : ///////////////
572 : // The maximum size is now computed: set the remaining parameters
573 0 : mBoundingMetrics.width = dx_left + bmBase.width + dx_right;
574 :
575 0 : mBoundingMetrics.leftBearing = NS_MIN(0, dx_left + bmBase.leftBearing);
576 : mBoundingMetrics.rightBearing =
577 0 : NS_MAX(mBoundingMetrics.width, dx_left + bmBase.rightBearing);
578 :
579 0 : aDesiredSize.width = mBoundingMetrics.width;
580 :
581 0 : aDesiredSize.ascent = NS_MAX(mBoundingMetrics.ascent, baseSize.ascent);
582 : aDesiredSize.height = aDesiredSize.ascent +
583 0 : NS_MAX(mBoundingMetrics.descent, baseSize.height - baseSize.ascent);
584 :
585 0 : if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
586 : // get the leading to be left at the top of the resulting frame
587 : // this seems more reliable than using fm->GetLeading() on suspicious
588 : // fonts
589 0 : nscoord leading = nscoord(0.2f * mEmHeight);
590 0 : nscoord desiredSizeAscent = aDesiredSize.ascent;
591 0 : nscoord desiredSizeDescent = aDesiredSize.height - aDesiredSize.ascent;
592 :
593 0 : if (IsToDraw(NOTATION_LONGDIV)) {
594 : desiredSizeAscent = NS_MAX(desiredSizeAscent,
595 0 : longdivAscent + leading);
596 : desiredSizeDescent = NS_MAX(desiredSizeDescent,
597 0 : longdivDescent + mRuleThickness);
598 : }
599 :
600 0 : if (IsToDraw(NOTATION_RADICAL)) {
601 : desiredSizeAscent = NS_MAX(desiredSizeAscent,
602 0 : radicalAscent + leading);
603 : desiredSizeDescent = NS_MAX(desiredSizeDescent,
604 0 : radicalDescent + mRuleThickness);
605 : }
606 :
607 0 : aDesiredSize.ascent = desiredSizeAscent;
608 0 : aDesiredSize.height = desiredSizeAscent + desiredSizeDescent;
609 : }
610 :
611 0 : if (IsToDraw(NOTATION_CIRCLE) ||
612 0 : IsToDraw(NOTATION_ROUNDEDBOX) ||
613 0 : (IsToDraw(NOTATION_TOP) && IsToDraw(NOTATION_BOTTOM))) {
614 : // center the menclose around the content (vertically)
615 : nscoord dy = NS_MAX(aDesiredSize.ascent - bmBase.ascent,
616 : aDesiredSize.height - aDesiredSize.ascent -
617 0 : bmBase.descent);
618 :
619 0 : aDesiredSize.ascent = bmBase.ascent + dy;
620 0 : aDesiredSize.height = aDesiredSize.ascent + bmBase.descent + dy;
621 : }
622 :
623 : // Update mBoundingMetrics ascent/descent
624 0 : if (IsToDraw(NOTATION_TOP) ||
625 0 : IsToDraw(NOTATION_RIGHT) ||
626 0 : IsToDraw(NOTATION_LEFT) ||
627 0 : IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
628 0 : IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
629 0 : IsToDraw(NOTATION_VERTICALSTRIKE) ||
630 0 : IsToDraw(NOTATION_CIRCLE) ||
631 0 : IsToDraw(NOTATION_ROUNDEDBOX))
632 0 : mBoundingMetrics.ascent = aDesiredSize.ascent;
633 :
634 0 : if (IsToDraw(NOTATION_BOTTOM) ||
635 0 : IsToDraw(NOTATION_RIGHT) ||
636 0 : IsToDraw(NOTATION_LEFT) ||
637 0 : IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
638 0 : IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
639 0 : IsToDraw(NOTATION_VERTICALSTRIKE) ||
640 0 : IsToDraw(NOTATION_CIRCLE) ||
641 0 : IsToDraw(NOTATION_ROUNDEDBOX))
642 0 : mBoundingMetrics.descent = aDesiredSize.height - aDesiredSize.ascent;
643 :
644 0 : aDesiredSize.mBoundingMetrics = mBoundingMetrics;
645 :
646 0 : mReference.x = 0;
647 0 : mReference.y = aDesiredSize.ascent;
648 :
649 0 : if (aPlaceOrigin) {
650 : //////////////////
651 : // Set position and size of MathMLChars
652 0 : if (IsToDraw(NOTATION_LONGDIV))
653 0 : mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left -
654 : bmLongdivChar.width,
655 : aDesiredSize.ascent -
656 : longdivAscent,
657 : bmLongdivChar.width,
658 : bmLongdivChar.ascent +
659 0 : bmLongdivChar.descent));
660 :
661 0 : if (IsToDraw(NOTATION_RADICAL)) {
662 : nscoord dx = NS_MATHML_IS_RTL(mPresentationData.flags) ?
663 0 : dx_left + bmBase.width : dx_left - bmRadicalChar.width;
664 :
665 0 : mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx,
666 : aDesiredSize.ascent -
667 : radicalAscent,
668 : bmRadicalChar.width,
669 : bmRadicalChar.ascent +
670 0 : bmRadicalChar.descent));
671 : }
672 :
673 0 : mContentWidth = bmBase.width;
674 :
675 : //////////////////
676 : // Finish reflowing child frames
677 0 : PositionRowChildFrames(dx_left, aDesiredSize.ascent);
678 : }
679 :
680 0 : return NS_OK;
681 : }
682 :
683 : nscoord
684 0 : nsMathMLmencloseFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
685 : {
686 0 : nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
687 0 : if (!gap)
688 0 : return 0;
689 :
690 : // Move the MathML characters
691 0 : nsRect rect;
692 0 : for (PRUint32 i = 0; i < mMathMLChar.Length(); i++) {
693 0 : mMathMLChar[i].GetRect(rect);
694 0 : rect.MoveBy(gap, 0);
695 0 : mMathMLChar[i].SetRect(rect);
696 : }
697 :
698 0 : return gap;
699 : }
700 :
701 : NS_IMETHODIMP
702 0 : nsMathMLmencloseFrame::AttributeChanged(PRInt32 aNameSpaceID,
703 : nsIAtom* aAttribute,
704 : PRInt32 aModType)
705 : {
706 0 : if (aAttribute == nsGkAtoms::notation_) {
707 0 : InitNotations();
708 : }
709 :
710 : return nsMathMLContainerFrame::
711 0 : AttributeChanged(aNameSpaceID, aAttribute, aModType);
712 : }
713 :
714 : //////////////////
715 : // the Style System will use these to pass the proper style context to our
716 : // MathMLChar
717 : nsStyleContext*
718 0 : nsMathMLmencloseFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
719 : {
720 0 : PRInt32 len = mMathMLChar.Length();
721 0 : if (aIndex >= 0 && aIndex < len)
722 0 : return mMathMLChar[aIndex].GetStyleContext();
723 : else
724 0 : return nsnull;
725 : }
726 :
727 : void
728 0 : nsMathMLmencloseFrame::SetAdditionalStyleContext(PRInt32 aIndex,
729 : nsStyleContext* aStyleContext)
730 : {
731 0 : PRInt32 len = mMathMLChar.Length();
732 0 : if (aIndex >= 0 && aIndex < len)
733 0 : mMathMLChar[aIndex].SetStyleContext(aStyleContext);
734 0 : }
735 :
736 : class nsDisplayNotation : public nsDisplayItem
737 : {
738 : public:
739 0 : nsDisplayNotation(nsDisplayListBuilder* aBuilder,
740 : nsIFrame* aFrame, const nsRect& aRect,
741 : nscoord aThickness, nsMencloseNotation aType)
742 : : nsDisplayItem(aBuilder, aFrame), mRect(aRect),
743 0 : mThickness(aThickness), mType(aType) {
744 0 : MOZ_COUNT_CTOR(nsDisplayNotation);
745 0 : }
746 : #ifdef NS_BUILD_REFCNT_LOGGING
747 0 : virtual ~nsDisplayNotation() {
748 0 : MOZ_COUNT_DTOR(nsDisplayNotation);
749 0 : }
750 : #endif
751 :
752 : virtual void Paint(nsDisplayListBuilder* aBuilder,
753 : nsRenderingContext* aCtx);
754 0 : NS_DISPLAY_DECL_NAME("MathMLMencloseNotation", TYPE_MATHML_MENCLOSE_NOTATION)
755 :
756 : private:
757 : nsRect mRect;
758 : nscoord mThickness;
759 : nsMencloseNotation mType;
760 : };
761 :
762 0 : void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
763 : nsRenderingContext* aCtx)
764 : {
765 : // get the gfxRect
766 0 : nsPresContext* presContext = mFrame->PresContext();
767 0 : gfxRect rect = presContext->AppUnitsToGfxUnits(mRect + ToReferenceFrame());
768 :
769 : // paint the frame with the current text color
770 0 : aCtx->SetColor(mFrame->GetVisitedDependentColor(eCSSProperty_color));
771 :
772 : // change line width to mThickness
773 0 : gfxContext *gfxCtx = aCtx->ThebesContext();
774 0 : gfxFloat currentLineWidth = gfxCtx->CurrentLineWidth();
775 0 : gfxFloat e = presContext->AppUnitsToGfxUnits(mThickness);
776 0 : gfxCtx->SetLineWidth(e);
777 :
778 0 : rect.Deflate(e / 2.0);
779 :
780 0 : gfxCtx->NewPath();
781 :
782 0 : switch(mType)
783 : {
784 : case NOTATION_CIRCLE:
785 0 : gfxCtx->Ellipse(rect.Center(), rect.Size());
786 0 : break;
787 :
788 : case NOTATION_ROUNDEDBOX:
789 0 : gfxCtx->RoundedRectangle(rect, gfxCornerSizes(3 * e), true);
790 0 : break;
791 :
792 : case NOTATION_UPDIAGONALSTRIKE:
793 0 : gfxCtx->Line(rect.BottomLeft(), rect.TopRight());
794 0 : break;
795 :
796 : case NOTATION_DOWNDIAGONALSTRIKE:
797 0 : gfxCtx->Line(rect.TopLeft(), rect.BottomRight());
798 0 : break;
799 :
800 : default:
801 0 : NS_NOTREACHED("This notation can not be drawn using nsDisplayNotation");
802 0 : break;
803 : }
804 :
805 0 : gfxCtx->Stroke();
806 :
807 : // restore previous line width
808 0 : gfxCtx->SetLineWidth(currentLineWidth);
809 0 : }
810 :
811 : nsresult
812 0 : nsMathMLmencloseFrame::DisplayNotation(nsDisplayListBuilder* aBuilder,
813 : nsIFrame* aFrame, const nsRect& aRect,
814 : const nsDisplayListSet& aLists,
815 : nscoord aThickness,
816 : nsMencloseNotation aType)
817 : {
818 0 : if (!aFrame->GetStyleVisibility()->IsVisible() || aRect.IsEmpty() ||
819 : aThickness <= 0)
820 0 : return NS_OK;
821 :
822 : return aLists.Content()->AppendNewToTop(new (aBuilder)
823 0 : nsDisplayNotation(aBuilder, aFrame, aRect, aThickness, aType));
824 : }
|