Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
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/. */
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>
15 //
16 // <mfrac> -- form a fraction from two subexpressions - implementation
17 //
19 // various fraction line thicknesses (multiplicative values of the default rule thickness)
21 #define THIN_FRACTION_LINE 0.5f
22 #define THIN_FRACTION_LINE_MINIMUM_PIXELS 1 // minimum of 1 pixel
24 #define THICK_FRACTION_LINE 2.0f
25 #define THICK_FRACTION_LINE_MINIMUM_PIXELS 2 // minimum of 2 pixels
27 nsIFrame*
28 NS_NewMathMLmfracFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
29 {
30 return new (aPresShell) nsMathMLmfracFrame(aContext);
31 }
33 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfracFrame)
35 nsMathMLmfracFrame::~nsMathMLmfracFrame()
36 {
37 }
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 }
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 }
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);
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 }
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 }
83 return NS_OK;
84 }
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;
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 }
133 // use minimum if the lineThickness is a non-zero value less than minimun
134 if (lineThickness && lineThickness < minimumThickness)
135 lineThickness = minimumThickness;
137 return lineThickness;
138 }
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);
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 }
158 /* virtual */ nsresult
159 nsMathMLmfracFrame::MeasureForWidth(nsRenderingContext& aRenderingContext,
160 nsHTMLReflowMetrics& aDesiredSize)
161 {
162 return PlaceInternal(aRenderingContext,
163 false,
164 aDesiredSize,
165 true);
166 }
168 nscoord
169 nsMathMLmfracFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
170 {
171 nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
172 if (!gap) return 0;
174 mLineRect.MoveBy(gap, 0);
175 return gap;
176 }
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 }
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);
214 nsPresContext* presContext = PresContext();
215 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
217 nsRefPtr<nsFontMetrics> fm;
218 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
219 aRenderingContext.SetFont(fm);
221 nscoord defaultRuleThickness, axisHeight;
222 GetRuleThickness(aRenderingContext, fm, defaultRuleThickness);
223 GetAxisHeight(aRenderingContext, fm, axisHeight);
225 bool outermostEmbellished = false;
226 if (mEmbellishData.coreFrame) {
227 nsEmbellishData parentData;
228 GetEmbellishDataFrom(mParent, parentData);
229 outermostEmbellished = parentData.coreFrame != mEmbellishData.coreFrame;
230 }
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);
238 // bevelled attribute
239 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::bevelled_, value);
240 mIsBevelled = value.EqualsLiteral("true");
242 if (!mIsBevelled) {
243 mLineRect.height = mLineThickness;
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 }
261 //////////////////
262 // Get shifts
263 nscoord numShift = 0;
264 nscoord denShift = 0;
266 // Rule 15b, App. G, TeXbook
267 nscoord numShift1, numShift2, numShift3;
268 nscoord denShift1, denShift2;
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 }
282 nscoord minClearance = 0;
283 nscoord actualClearance = 0;
285 nscoord actualRuleThickness = mLineThickness;
287 if (0 == actualRuleThickness) {
288 // Rule 15c, App. G, TeXbook
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
305 // min clearance between numerator or denominator and middle of bar
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;
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;
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 }
333 //////////////////
334 // Place Children
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;
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();
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();
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;
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;
375 mReference.x = 0;
376 mReference.y = aDesiredSize.TopAscent();
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;
397 // Define the constant used in the expression of the maximum width
398 nscoord em = fm->EmHeight();
399 nscoord slashMaxWidthConstant = 2 * em;
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);
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;
416 // ___________
417 // | | /
418 // {|-NUMERATOR-| /
419 // {|___________| S
420 // { L
421 // numShift{ A
422 // ------------------------------------------------------- baseline
423 // S _____________ } denShift
424 // H | |}
425 // / |-DENOMINATOR-|}
426 // / |_____________|
427 //
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 }
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 }
449 // Set the ascent/descent of our BoundingMetrics.
450 mBoundingMetrics.ascent = bmNum.ascent + numShift;
451 mBoundingMetrics.descent = bmDen.descent + denShift;
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 }
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 }
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;
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;
492 mReference.x = 0;
493 mReference.y = aDesiredSize.TopAscent();
495 if (aPlaceOrigin) {
496 nscoord dx, dy;
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);
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);
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 }
518 }
520 return NS_OK;
521 }
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
538 virtual void Paint(nsDisplayListBuilder* aBuilder,
539 nsRenderingContext* aCtx) MOZ_OVERRIDE;
540 NS_DISPLAY_DECL_NAME("MathMLSlash", TYPE_MATHML_SLASH)
542 private:
543 nsRect mRect;
544 nscoord mThickness;
545 bool mRTL;
546 };
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());
555 // paint with the current text color
556 aCtx->SetColor(mFrame->GetVisitedDependentColor(eCSSProperty_color));
558 // draw the slash as a parallelogram
559 gfxContext *gfxCtx = aCtx->ThebesContext();
560 gfxPoint delta = gfxPoint(presContext->AppUnitsToGfxUnits(mThickness), 0);
561 gfxCtx->NewPath();
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 }
575 gfxCtx->ClosePath();
576 gfxCtx->Fill();
577 }
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;
587 aLists.Content()->AppendNewToTop(new (aBuilder)
588 nsDisplayMathMLSlash(aBuilder, aFrame, aRect, aThickness,
589 StyleVisibility()->mDirection));
590 }