1 /*******************************************************************************
\r
2 * Copyright (c) 2006 Sybase, Inc. and others.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * Sybase, Inc. - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.eclipse.jst.pagedesigner.css2.layout;
\r
14 import java.util.ArrayList;
\r
15 import java.util.List;
\r
17 import org.eclipse.draw2d.FigureUtilities;
\r
18 import org.eclipse.draw2d.Graphics;
\r
19 import org.eclipse.draw2d.geometry.Insets;
\r
20 import org.eclipse.draw2d.geometry.Rectangle;
\r
21 import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
\r
22 import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
\r
23 import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyMeta;
\r
24 import org.eclipse.jst.pagedesigner.css2.style.ITagEditInfo;
\r
25 import org.eclipse.jst.pagedesigner.css2.value.Length;
\r
26 import org.eclipse.jst.pagedesigner.css2.widget.BorderUtil;
\r
27 import org.eclipse.swt.graphics.FontMetrics;
\r
30 * The block layout for {@link CSSFigure}figures. Basic code structure is from
\r
35 public class CSSBlockFlowLayout extends CSSLayout implements ICSSPainter2 {
\r
36 private LineBox _previousLine = null;
\r
39 * the block box for the layout object
\r
41 protected BlockBox _blockBox = null;
\r
44 * The font metrics for this layout object
\r
46 protected FontMetrics _fontMetrices;
\r
48 int _userSpecifiedWidth;
\r
50 int _userSpecifiedHeight;
\r
53 * whether we need HScroll and VScroll when overflow is set to "scroll".
\r
54 * will be updated in "endBlock" and used in "paintFigurePostClientArea"
\r
56 boolean _needHScroll = false;
\r
58 boolean _needVScroll = false;
\r
61 * Creates a new CSSBlockFlowLayout with the given BlockFlow.
\r
64 public CSSBlockFlowLayout(CSSFigure cssfigure) {
\r
69 * @return true if this layout box has more than one line
\r
71 protected boolean hasMoreThanOneLine() {
\r
72 return _previousLine != null;
\r
76 * @return true if this layout block is inline
\r
78 public boolean isInlineBlock() {
\r
79 String obj = getCSSStyle().getDisplay();
\r
80 return ICSSPropertyID.VAL_INLINE_BLOCK.equals(obj)
\r
81 || ICSSPropertyID.VAL_INLINE_TABLE.equals(obj);
\r
85 * @return true if should expand the width to all available width.
\r
87 public boolean shouldExpand() {
\r
88 ICSSStyle style = getCSSStyle();
\r
89 if (style == null) {
\r
92 return "block".equalsIgnoreCase(style.getDisplay()) //$NON-NLS-1$
\r
93 || "list-item".equalsIgnoreCase(style.getDisplay()); //$NON-NLS-1$
\r
96 // ---------------------------------------------------------------------------------------------------
\r
97 // preLayout stage. Major job is get the top-left corner information of the
\r
101 * sets up the single block that contains all of the lines.
\r
103 protected void setupBlock() {
\r
104 // int recommended = line.getAvailableWidth();
\r
105 // if (recommended != previousRecommendedWidth)
\r
106 // Remove all current Fragments
\r
108 // Ask for a new line, in case we are in the middle of a line
\r
110 if (!isInlineBlock()) {
\r
111 LineBox lineBox = getFlowContext().getCurrentLine();
\r
112 if (lineBox != null && !lineBox.isEmptyStringLine()) {
\r
113 getFlowContext().endLine();
\r
117 ICSSStyle style = getCSSStyle();
\r
119 // endLine will result in context create a new line, so we are in the
\r
121 // passing in the top margin, and context will consider that when create
\r
123 int marginTop = style.getMarginInsets().top;
\r
124 LineBox line = getFlowContext().getCurrentLine(marginTop);
\r
126 // Setup the one fragment for this Block with the correct X and
\r
129 // FIXME: according to spec, when using percentage width/height, should
\r
131 // the "containing block". But we don't have very good "containing
\r
132 // block" resolution
\r
133 // implementation yet.
\r
135 // calculate the min size
\r
136 // int minWidth = 0;
\r
137 // int minHeight = 0;
\r
138 // if (style != null)
\r
140 // // try to see whether there is any designer specified min size
\r
141 // ITagEditInfo info = (ITagEditInfo)
\r
142 // style.getAdapter(ITagEditInfo.class);
\r
143 // if (info != null)
\r
145 // minWidth = info.getMinWidth();
\r
146 // minHeight = info.getMinHeight();
\r
149 // // CSS also has the min-width/min-height property. We should also get
\r
151 // // and using the max of the "min-width" css property and the designer
\r
152 // specified min size.
\r
153 // int height = getLengthValue(style,ICSSPropertyID.ATTR_MIN_HEIGHT);
\r
154 // if(height > minHeight)
\r
156 // minHeight = height;
\r
158 // int width = getLengthValue(style,ICSSPropertyID.ATTR_MIN_WIDTH);
\r
159 // if(width > minWidth)
\r
161 // minWidth = width;
\r
165 // keep track of user specified size, this will be used when handling
\r
166 // the "overflow" CSS property.
\r
167 _userSpecifiedWidth = 0;
\r
168 _userSpecifiedHeight = 0;
\r
171 int width = getLengthValue(style, ICSSPropertyID.ATTR_WIDTH);
\r
173 int availableWidth = line.getAvailableWidth()
\r
174 - style.getMarginInsets().getWidth();
\r
176 // no width setting
\r
177 if (isCalculatingMaxWidth()) {
\r
178 _blockBox.setRecommendedWidth(Integer.MAX_VALUE);
\r
179 // _blockBox.setWidth( (minWidth>0?minWidth:0));
\r
181 _blockBox.setRecommendedWidth(availableWidth);
\r
182 if (shouldExpand()) {
\r
183 _blockBox.setWidth(availableWidth);
\r
185 // _blockBox.setWidth( (minWidth>0?minWidth:0));
\r
190 if (!style.isSizeIncludeBorderPadding()) {
\r
191 w += style.getBorderInsets().getWidth()
\r
192 + style.getPaddingInsets().getWidth();
\r
194 // XXX: should we use minWidth or follow user's choice?
\r
195 // if (w < minWidth)
\r
199 _userSpecifiedWidth = w;
\r
200 _blockBox.setWidth(w);
\r
201 _blockBox.setRecommendedWidth(w);
\r
206 int height = getLengthValue(style, ICSSPropertyID.ATTR_HEIGHT);
\r
208 // style.getStyleProperty(ICSSPropertyID.ATTR_HEIGHT);
\r
209 // Length heightLength = (height instanceof Length) ? (Length)
\r
213 // if (minHeight > 0)
\r
215 // // _blockBox.setHeight(minHeight);
\r
216 // _blockBox.setRecommendedHeight(minHeight);
\r
220 _blockBox.setHeight(0);
\r
221 _blockBox.setRecommendedHeight(0);
\r
225 if (handlingBorderForBlock()
\r
226 && !style.isSizeIncludeBorderPadding()) {
\r
227 h += style.getBorderInsets().getHeight()
\r
228 + style.getPaddingInsets().getHeight();
\r
230 // XXX: should we follow minHeight or user's choice?
\r
231 // if (minHeight > h)
\r
235 _userSpecifiedHeight = h;
\r
236 _blockBox.setHeight(h);
\r
237 _blockBox.setRecommendedHeight(h);
\r
240 _blockBox.setMarginInsets(new Insets(style.getMarginInsets()));
\r
241 if (handlingBorderForBlock()) {
\r
242 BoxUtil.setupBorderPaddingMargin(_blockBox, getCSSStyle());
\r
245 // as in designer, we don't want to the element to have zero size, so
\r
246 // set a minimun size here.
\r
247 // _blockBox.setWidth(Math.max(20, _blockBox.getWidth()));
\r
248 // int minHeight = getCSSStyle().getCSSFont().getFontSize() +
\r
249 // _blockBox.getBorderPaddingHeight();
\r
250 // _blockBox.setHeight(Math.max(minHeight, _blockBox.getHeight()));
\r
252 _blockBox._y = line._y;
\r
253 _blockBox._x = line._x;
\r
255 setBlockVerticalAlign(_blockBox);
\r
261 * @return the length value
\r
263 protected int getLengthValue(ICSSStyle style, String property) {
\r
264 int lengthValue = 0;
\r
265 if (style != null) {
\r
266 Object object = style.getStyleProperty(property);
\r
267 Length lengthObj = (object instanceof Length) ? (Length) object
\r
270 if (lengthObj != null) {
\r
271 lengthValue = lengthObj.getValue();
\r
272 if (lengthObj.isPercentage()) {
\r
273 if (ICSSPropertyID.ATTR_WIDTH.equalsIgnoreCase(property)
\r
274 || ICSSPropertyID.ATTR_MIN_WIDTH
\r
275 .equalsIgnoreCase(property)) {
\r
276 lengthValue = this.getFlowContext().getCurrentLine().getRecommendedContentWidth()
\r
277 * lengthValue / 100;
\r
278 } else if (ICSSPropertyID.ATTR_HEIGHT
\r
279 .equalsIgnoreCase(property)
\r
280 || ICSSPropertyID.ATTR_MIN_HEIGHT
\r
281 .equalsIgnoreCase(property)) {
\r
282 // XXX: we should omit it because we don't support
\r
283 // percentage height now.
\r
289 return lengthValue;
\r
292 private void setBlockVerticalAlign(BlockBox box) {
\r
293 ICSSStyle style = getCSSStyle();
\r
294 if (style != null) {
\r
295 box.setVerticalAlignData(style
\r
296 .getStyleProperty(ICSSPropertyID.ATTR_VERTICAL_ALIGN));
\r
301 * @see FlowContainerLayout#preLayout()
\r
303 protected void preLayout() {
\r
305 _blockBox = new BlockBox();
\r
307 // Probably could setup current and previous line here, or just previous
\r
310 // -------------------------------------------------------------------------------------------------------
\r
312 * layout the lines in this layout
\r
314 protected void layoutLines() {
\r
315 List lines = _blockBox.getFragments();
\r
316 if (lines != null) {
\r
317 for (int i = 0; i < lines.size(); i++) {
\r
318 if (lines.get(i) instanceof LineBox) {
\r
319 layoutLine((LineBox) lines.get(i));
\r
326 * Called by flush(), adds the BlockBox associated with this BlockFlowLayout
\r
327 * to the current line and then ends the line.
\r
329 protected void endBlock() {
\r
331 ICSSStyle style = getCSSStyle();
\r
332 if (style != null) {
\r
335 // try to see whether there is any designer specified min size
\r
336 ITagEditInfo info = (ITagEditInfo) style
\r
337 .getAdapter(ITagEditInfo.class);
\r
338 if (info != null) {
\r
339 minWidth = info.getMinWidth();
\r
340 minHeight = info.getMinHeight();
\r
343 // CSS also has the min-width/min-height property. We should also
\r
345 // and using the max of the "min-width" css property and the
\r
346 // designer specified min size.
\r
347 int height = getLengthValue(style, ICSSPropertyID.ATTR_MIN_HEIGHT);
\r
348 if (height > minHeight) {
\r
349 minHeight = height;
\r
351 int width = getLengthValue(style, ICSSPropertyID.ATTR_MIN_WIDTH);
\r
352 if (width > minWidth) {
\r
355 if (minHeight > _blockBox.getHeight()) {
\r
356 _blockBox.setHeight(minHeight);
\r
358 if (minWidth > _blockBox.getWidth()) {
\r
359 _blockBox.setWidth(minWidth);
\r
363 // reset scroll information.
\r
364 this._needHScroll = this._needVScroll = false;
\r
366 // ok, now we need to adjust the _blockBox's size according to the
\r
367 // "overflow" setting.
\r
368 // depends on different "overflow" style of this block, different sizing
\r
369 // policy may apply.
\r
370 // ICSSStyle style = this.getCSSStyle();
\r
371 if (style != null) {
\r
372 Object overflow = style
\r
373 .getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);
\r
374 if (ICSSPropertyID.VAL_HIDDEN.equals(overflow)) {
\r
375 if (_userSpecifiedWidth > 0) {
\r
376 _blockBox.setWidth(_userSpecifiedWidth);
\r
378 if (_userSpecifiedHeight > 0) {
\r
379 _blockBox.setHeight(_userSpecifiedHeight);
\r
381 } else if (ICSSPropertyID.VAL_SCROLL.equals(overflow)
\r
382 || ICSSPropertyID.VAL_AUTO.equals(overflow)) {
\r
383 // adjust _needHScroll and _needVScroll
\r
384 if (_userSpecifiedWidth > 0
\r
385 && _userSpecifiedWidth < _blockBox.getWidth()) {
\r
386 _needHScroll = true;
\r
388 if (_userSpecifiedHeight > 0
\r
389 && _userSpecifiedHeight < _blockBox.getHeight()) {
\r
390 _needVScroll = true;
\r
392 if (_needHScroll && !_needVScroll) {
\r
393 if (_userSpecifiedHeight > 0
\r
394 && _blockBox.getInternalContentHeight() >= 0
\r
395 && _userSpecifiedHeight < _blockBox
\r
396 .getInternalContentHeight()
\r
397 + _blockBox.getPaddingInsets().getHeight()
\r
398 + BorderUtil.SCROLL_WIDTH) {
\r
399 _needVScroll = true;
\r
402 if (!_needHScroll && _needVScroll) {
\r
403 if (_userSpecifiedWidth > 0
\r
404 && _blockBox.getInternalContentWidth() >= 0
\r
405 && _userSpecifiedWidth < _blockBox
\r
406 .getInternalContentWidth()
\r
407 + _blockBox.getPaddingInsets().getWidth()
\r
408 + BorderUtil.SCROLL_WIDTH) {
\r
409 _needHScroll = true;
\r
413 if (_userSpecifiedWidth > 0) {
\r
414 _blockBox.setWidth(_userSpecifiedWidth);
\r
416 if (_userSpecifiedHeight > 0) {
\r
417 _blockBox.setHeight(_userSpecifiedHeight);
\r
422 if (getFlowContext().isCurrentLineOccupied()
\r
423 && getFlowContext().getCurrentLine().getAvailableWidth() < _blockBox._width
\r
424 + _blockBox.getMarginInsets().getWidth()) {
\r
425 getFlowContext().endLine();
\r
427 if (!isInlineBlock()) {
\r
428 LineBox line = getFlowContext().getCurrentLine();
\r
429 line.setHorizonalData(getCSSStyle().getStyleProperty(
\r
430 ICSSPropertyID.ATTR_HORIZONTAL_ALIGN));
\r
431 line.setHtmlInitData(getCSSStyle().getHTMLelementInitValue(
\r
432 ICSSPropertyID.ATTR_HORIZONTAL_ALIGN));
\r
433 line.add(_blockBox);
\r
434 // getFlowContext().addToCurrentLine(_blockBox);
\r
436 getFlowContext().addToCurrentLine(_blockBox);
\r
438 getFlowContext().getCurrentLine().getMarginInsets().bottom = getCSSStyle()
\r
439 .getMarginInsets().bottom;
\r
441 if (!isInlineBlock()) {
\r
442 getFlowContext().endLine();
\r
449 protected void layoutLine(LineBox line) {
\r
450 // currentLine.x = 0; //XXX: comment out, don't understand why set to 0,
\r
451 // because it has already
\r
452 // been set when setupLine(). And if do need, should
\r
453 // set to getBorderPaddingInsets().left
\r
454 // if (!isInlineBlock() && shouldExpand())
\r
456 // FIXME: currently we are using getRecommendedContentWidth,
\r
457 // what happen if after adding the new line, the new width is bigger
\r
459 // recommendedContentWidth? should we use getWidth() instead of
\r
460 // recommendedcontentWidth?
\r
461 Object textalign = line.getHorizonalData();
\r
462 if (textalign == null
\r
463 || ICSSPropertyMeta.NOT_SPECIFIED.equals(textalign)) {
\r
464 textalign = (getCSSStyle()
\r
465 .getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));
\r
467 if (textalign == null
\r
468 || ICSSPropertyMeta.NOT_SPECIFIED.equals(textalign)) {
\r
469 textalign = line.getHtmlInitData();
\r
471 if (ICSSPropertyID.VAL_RIGHT.equals(textalign)) {
\r
472 line._x = _blockBox.getContentWidth() - line.getWidth();
\r
473 } else if (ICSSPropertyID.VAL_CENTER.equals(textalign)) {
\r
474 line._x = (_blockBox.getContentWidth() - line.getWidth()) / 2;
\r
484 * Adjust all fragments in the current line to have the same baseline. Do
\r
485 * any additional adjustments, such as horizontal alignment.
\r
487 protected void addCurrentLine() {
\r
488 // The follow code is commented out, and moved into layoutLine(line)
\r
489 // called by endBlock().
\r
490 // since only when endBlock is called we really know how big is this
\r
491 // block box, and then can
\r
492 // do horizontal alignment.
\r
493 // // currentLine.x = 0; //XXX: comment out, don't understand why set to
\r
494 // 0, because it has already
\r
495 // // been set when setupLine(). And if do need, should
\r
496 // // set to getBorderPaddingInsets().left
\r
497 // if (!isInlineBlock() && shouldExpand())
\r
499 // // FIXME: currently we are using getRecommendedContentWidth,
\r
500 // // what happen if after adding the new line, the new width is bigger
\r
502 // // recommendedContentWidth? should we use getWidth() instead of
\r
503 // // recommendedcontentWidth?
\r
505 // Object textalign =
\r
506 // (getCSSStyle().getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));
\r
507 // if (textalign == ICSSPropertyID.VAL_RIGHT)
\r
509 // _currentLine._x = _blockBox.getContentWidth() +
\r
510 // _blockBox.getBorderPaddingInsets().left - _currentLine.getWidth();
\r
512 // else if (textalign == ICSSPropertyID.VAL_CENTER)
\r
515 // _currentLine._x = _blockBox.getBorderPaddingInsets().left +
\r
516 // (_blockBox.getContentWidth() - _currentLine.getWidth()) / 2;
\r
518 // if (_currentLine._x < 0)
\r
519 // _currentLine._x = 0;
\r
522 // // FIXME: should check vertical alignment here?
\r
523 // _currentLine.commit();
\r
525 // layoutLine(_currentLine);
\r
526 _blockBox.add(_currentLine);
\r
530 * @see FlowContainerLayout#flush()
\r
532 protected void flush() {
\r
533 if (_currentLine != null && _currentLine.isOccupied()) {
\r
540 * @see FlowContainerLayout#cleanup()
\r
542 protected void cleanup() {
\r
543 _currentLine = _previousLine = null;
\r
544 _fontMetrices = null;
\r
547 // ----------------------------------------------------------------------------------
\r
550 * Override to setup the line's x, remaining, and available width.
\r
553 * the LineBox to set up
\r
554 * @param topMargin
\r
556 protected void setupLine(LineBox line, int topMargin) {
\r
559 // the caller of getCurrentLine() may add leftMargin and leftPadding and
\r
560 // leftBorder to line.x
\r
563 // FIXME: here should check the floating boxes, and minus the width of
\r
566 line.setRecommendedWidth(_blockBox.getRecommendedContentWidth());
\r
567 if (_previousLine == null) {
\r
569 if (topMargin != Integer.MIN_VALUE) {
\r
570 line._y += topMargin;
\r
573 if (topMargin == Integer.MIN_VALUE) {
\r
574 line._y = _previousLine._y + _previousLine.getHeight()
\r
575 + getLinePadding() + _previousLine.getMarginInsets().bottom; // XXX:
\r
582 line._y = _previousLine._y
\r
583 + _previousLine.getHeight()
\r
584 + Math.max(topMargin,
\r
585 _previousLine.getMarginInsets().bottom);
\r
588 setFontinfoForLine(line);
\r
589 // line.validate();
\r
592 private void setFontinfoForLine(LineBox line) {
\r
594 ICSSStyle style = getCSSStyle();
\r
595 if (style != null) {
\r
596 if (_fontMetrices == null) {
\r
597 // as getSwtFont is resource consuming, so we cache the
\r
599 _fontMetrices = FigureUtilities.getFontMetrics(style
\r
600 .getCSSFont().getSwtFont());
\r
602 line.setFontMetrics(_fontMetrices);
\r
607 * @see FlowContainerLayout#createNewLine()
\r
609 protected void createNewLine() {
\r
610 _currentLine = new LineBox();
\r
611 setupLine(_currentLine, Integer.MIN_VALUE);
\r
614 protected void createNewLine(int topmargin) {
\r
615 _currentLine = new LineBox();
\r
616 setupLine(_currentLine, topmargin);
\r
620 * @see FlowContext#endLine()
\r
622 public void endLine() {
\r
623 // this is called from child layouts.
\r
624 // If there is no current line, state is equivalent to new line
\r
625 if (_currentLine == null) {
\r
628 if (_currentLine.isOccupied()) {
\r
629 addCurrentLine(); // finalize the current line layout
\r
631 _currentLine = null;
\r
635 LineBox box = _currentLine;
\r
636 // _currentLine = _previousLine; //XXX: ???? why (yang)
\r
637 _previousLine = box;
\r
639 _currentLine = null;
\r
640 // setupLine(getCurrentLine());
\r
644 * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentY()
\r
646 public int getCurrentY() {
\r
647 return getCurrentLine()._y; // FIXME: margin of previous block?
\r
650 int getLinePadding() {
\r
657 * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#useLocalCoordinates()
\r
659 public boolean useLocalCoordinates() {
\r
666 * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#dispose()
\r
668 public void dispose() {
\r
675 * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#getFragmentsForRead()
\r
677 public List getFragmentsForRead() {
\r
678 List r = new ArrayList(1);
\r
686 * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#postValidate()
\r
688 public void postValidate() {
\r
690 Rectangle r = new Rectangle(_blockBox._x, _blockBox._y, _blockBox
\r
691 .getWidth(), _blockBox.getHeight());
\r
692 getCSSFigure().setBounds(r);
\r
693 List list = getCSSFigure().getChildren();
\r
694 for (int i = 0; i < list.size(); i++) {
\r
695 ((FlowFigure) list.get(i)).postValidate();
\r
702 * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getContainerWidth()
\r
704 public int getContainerWidth() {
\r
705 int width = Math.max(0, Math.max(_blockBox.getWidth(), _blockBox
\r
706 .getRecommendedWidth()));
\r
711 * when the "overflow" is "scroll", we need to paint the scrollbar
\r
713 public void paintFigurePostClientArea(Graphics g) {
\r
714 ICSSStyle style = this.getCSSStyle();
\r
715 if (style != null) {
\r
716 Object overflow = style
\r
717 .getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);
\r
718 if (ICSSPropertyID.VAL_SCROLL.equals(overflow)
\r
719 || ICSSPropertyID.VAL_AUTO.equals(overflow)) {
\r
720 if (this._needHScroll || this._needVScroll) {
\r
721 // as this is using localCoordinate, so translate to
\r
722 // relative to left/up corder of whole
\r
724 g.translate(-_blockBox.getBorderPaddingInsets().left,
\r
725 -_blockBox.getBorderPaddingInsets().top);
\r
727 Rectangle rect = new Rectangle(0, 0, _blockBox.getWidth(),
\r
728 _blockBox.getHeight());
\r
729 rect.crop(_blockBox.getBorderInsets());
\r
731 if (this._needHScroll && this._needVScroll) {
\r
732 BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,
\r
733 rect, BorderUtil.BOTH);
\r
734 } else if (this._needHScroll) {
\r
735 BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,
\r
736 rect, BorderUtil.HORIZONTAL_BAR);
\r
737 } else if (this._needVScroll) {
\r
738 BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,
\r
739 rect, BorderUtil.VERTICAL_BAR);
\r