Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / resolver / CSSToStyleMap.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "core/css/resolver/CSSToStyleMap.h"
30
31 #include "core/CSSValueKeywords.h"
32 #include "core/animation/css/CSSAnimationData.h"
33 #include "core/css/CSSBorderImageSliceValue.h"
34 #include "core/css/CSSPrimitiveValue.h"
35 #include "core/css/CSSPrimitiveValueMappings.h"
36 #include "core/css/CSSTimingFunctionValue.h"
37 #include "core/css/Pair.h"
38 #include "core/css/Rect.h"
39 #include "core/css/resolver/StyleResolverState.h"
40 #include "core/rendering/style/BorderImageLengthBox.h"
41 #include "core/rendering/style/FillLayer.h"
42
43 namespace blink {
44
45 const CSSToLengthConversionData& CSSToStyleMap::cssToLengthConversionData() const
46 {
47     return m_state.cssToLengthConversionData();
48 }
49
50 PassRefPtr<StyleImage> CSSToStyleMap::styleImage(CSSPropertyID propertyId, CSSValue* value)
51 {
52     return m_elementStyleResources.styleImage(m_state.document(), m_state.document().textLinkColors(), m_state.style()->color(), propertyId, value);
53 }
54
55 void CSSToStyleMap::mapFillAttachment(FillLayer* layer, CSSValue* value) const
56 {
57     if (value->isInitialValue()) {
58         layer->setAttachment(FillLayer::initialFillAttachment(layer->type()));
59         return;
60     }
61
62     if (!value->isPrimitiveValue())
63         return;
64
65     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
66     switch (primitiveValue->getValueID()) {
67     case CSSValueFixed:
68         layer->setAttachment(FixedBackgroundAttachment);
69         break;
70     case CSSValueScroll:
71         layer->setAttachment(ScrollBackgroundAttachment);
72         break;
73     case CSSValueLocal:
74         layer->setAttachment(LocalBackgroundAttachment);
75         break;
76     default:
77         return;
78     }
79 }
80
81 void CSSToStyleMap::mapFillClip(FillLayer* layer, CSSValue* value) const
82 {
83     if (value->isInitialValue()) {
84         layer->setClip(FillLayer::initialFillClip(layer->type()));
85         return;
86     }
87
88     if (!value->isPrimitiveValue())
89         return;
90
91     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
92     layer->setClip(*primitiveValue);
93 }
94
95 void CSSToStyleMap::mapFillComposite(FillLayer* layer, CSSValue* value) const
96 {
97     if (value->isInitialValue()) {
98         layer->setComposite(FillLayer::initialFillComposite(layer->type()));
99         return;
100     }
101
102     if (!value->isPrimitiveValue())
103         return;
104
105     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
106     layer->setComposite(*primitiveValue);
107 }
108
109 void CSSToStyleMap::mapFillBlendMode(FillLayer* layer, CSSValue* value) const
110 {
111     if (value->isInitialValue()) {
112         layer->setBlendMode(FillLayer::initialFillBlendMode(layer->type()));
113         return;
114     }
115
116     if (!value->isPrimitiveValue())
117         return;
118
119     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
120     layer->setBlendMode(*primitiveValue);
121 }
122
123 void CSSToStyleMap::mapFillOrigin(FillLayer* layer, CSSValue* value) const
124 {
125     if (value->isInitialValue()) {
126         layer->setOrigin(FillLayer::initialFillOrigin(layer->type()));
127         return;
128     }
129
130     if (!value->isPrimitiveValue())
131         return;
132
133     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
134     layer->setOrigin(*primitiveValue);
135 }
136
137
138 void CSSToStyleMap::mapFillImage(FillLayer* layer, CSSValue* value)
139 {
140     if (value->isInitialValue()) {
141         layer->setImage(FillLayer::initialFillImage(layer->type()));
142         return;
143     }
144
145     CSSPropertyID property = layer->type() == BackgroundFillLayer ? CSSPropertyBackgroundImage : CSSPropertyWebkitMaskImage;
146     layer->setImage(styleImage(property, value));
147 }
148
149 void CSSToStyleMap::mapFillRepeatX(FillLayer* layer, CSSValue* value) const
150 {
151     if (value->isInitialValue()) {
152         layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type()));
153         return;
154     }
155
156     if (!value->isPrimitiveValue())
157         return;
158
159     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
160     layer->setRepeatX(*primitiveValue);
161 }
162
163 void CSSToStyleMap::mapFillRepeatY(FillLayer* layer, CSSValue* value) const
164 {
165     if (value->isInitialValue()) {
166         layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type()));
167         return;
168     }
169
170     if (!value->isPrimitiveValue())
171         return;
172
173     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
174     layer->setRepeatY(*primitiveValue);
175 }
176
177 void CSSToStyleMap::mapFillSize(FillLayer* layer, CSSValue* value) const
178 {
179     if (value->isInitialValue()) {
180         layer->setSizeType(FillLayer::initialFillSizeType(layer->type()));
181         layer->setSizeLength(FillLayer::initialFillSizeLength(layer->type()));
182         return;
183     }
184
185     if (!value->isPrimitiveValue())
186         return;
187
188     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
189     if (primitiveValue->getValueID() == CSSValueContain)
190         layer->setSizeType(Contain);
191     else if (primitiveValue->getValueID() == CSSValueCover)
192         layer->setSizeType(Cover);
193     else
194         layer->setSizeType(SizeLength);
195
196     LengthSize b = FillLayer::initialFillSizeLength(layer->type());
197
198     if (primitiveValue->getValueID() == CSSValueContain || primitiveValue->getValueID() == CSSValueCover) {
199         layer->setSizeLength(b);
200         return;
201     }
202
203     Length firstLength;
204     Length secondLength;
205
206     if (Pair* pair = primitiveValue->getPairValue()) {
207         firstLength = pair->first()->convertToLength<AnyConversion>(cssToLengthConversionData());
208         secondLength = pair->second()->convertToLength<AnyConversion>(cssToLengthConversionData());
209     } else {
210         firstLength = primitiveValue->convertToLength<AnyConversion>(cssToLengthConversionData());
211         secondLength = Length();
212     }
213
214     b.setWidth(firstLength);
215     b.setHeight(secondLength);
216     layer->setSizeLength(b);
217 }
218
219 void CSSToStyleMap::mapFillXPosition(FillLayer* layer, CSSValue* value) const
220 {
221     if (value->isInitialValue()) {
222         layer->setXPosition(FillLayer::initialFillXPosition(layer->type()));
223         return;
224     }
225
226     if (!value->isPrimitiveValue())
227         return;
228
229     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
230     Pair* pair = primitiveValue->getPairValue();
231     if (pair)
232         primitiveValue = pair->second();
233
234     Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
235
236     layer->setXPosition(length);
237     if (pair)
238         layer->setBackgroundXOrigin(*(pair->first()));
239 }
240
241 void CSSToStyleMap::mapFillYPosition(FillLayer* layer, CSSValue* value) const
242 {
243     if (value->isInitialValue()) {
244         layer->setYPosition(FillLayer::initialFillYPosition(layer->type()));
245         return;
246     }
247
248     if (!value->isPrimitiveValue())
249         return;
250
251     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
252     Pair* pair = primitiveValue->getPairValue();
253     if (pair)
254         primitiveValue = pair->second();
255
256     Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
257
258     layer->setYPosition(length);
259     if (pair)
260         layer->setBackgroundYOrigin(*(pair->first()));
261 }
262
263 void CSSToStyleMap::mapFillMaskSourceType(FillLayer* layer, CSSValue* value) const
264 {
265     EMaskSourceType type = FillLayer::initialFillMaskSourceType(layer->type());
266     if (value->isInitialValue()) {
267         layer->setMaskSourceType(type);
268         return;
269     }
270
271     if (!value->isPrimitiveValue())
272         return;
273
274     switch (toCSSPrimitiveValue(value)->getValueID()) {
275     case CSSValueAlpha:
276         type = MaskAlpha;
277         break;
278     case CSSValueLuminance:
279         type = MaskLuminance;
280         break;
281     case CSSValueAuto:
282         break;
283     default:
284         ASSERT_NOT_REACHED();
285     }
286
287     layer->setMaskSourceType(type);
288 }
289
290 double CSSToStyleMap::mapAnimationDelay(CSSValue* value)
291 {
292     if (value->isInitialValue())
293         return CSSTimingData::initialDelay();
294     return toCSSPrimitiveValue(value)->computeSeconds();
295 }
296
297 Timing::PlaybackDirection CSSToStyleMap::mapAnimationDirection(CSSValue* value)
298 {
299     if (value->isInitialValue())
300         return CSSAnimationData::initialDirection();
301
302     switch (toCSSPrimitiveValue(value)->getValueID()) {
303     case CSSValueNormal:
304         return Timing::PlaybackDirectionNormal;
305     case CSSValueAlternate:
306         return Timing::PlaybackDirectionAlternate;
307     case CSSValueReverse:
308         return Timing::PlaybackDirectionReverse;
309     case CSSValueAlternateReverse:
310         return Timing::PlaybackDirectionAlternateReverse;
311     default:
312         ASSERT_NOT_REACHED();
313         return CSSAnimationData::initialDirection();
314     }
315 }
316
317 double CSSToStyleMap::mapAnimationDuration(CSSValue* value)
318 {
319     if (value->isInitialValue())
320         return CSSTimingData::initialDuration();
321     return toCSSPrimitiveValue(value)->computeSeconds();
322 }
323
324 Timing::FillMode CSSToStyleMap::mapAnimationFillMode(CSSValue* value)
325 {
326     if (value->isInitialValue())
327         return CSSAnimationData::initialFillMode();
328
329     switch (toCSSPrimitiveValue(value)->getValueID()) {
330     case CSSValueNone:
331         return Timing::FillModeNone;
332     case CSSValueForwards:
333         return Timing::FillModeForwards;
334     case CSSValueBackwards:
335         return Timing::FillModeBackwards;
336     case CSSValueBoth:
337         return Timing::FillModeBoth;
338     default:
339         ASSERT_NOT_REACHED();
340         return CSSAnimationData::initialFillMode();
341     }
342 }
343
344 double CSSToStyleMap::mapAnimationIterationCount(CSSValue* value)
345 {
346     if (value->isInitialValue())
347         return CSSAnimationData::initialIterationCount();
348     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
349     if (primitiveValue->getValueID() == CSSValueInfinite)
350         return std::numeric_limits<double>::infinity();
351     return primitiveValue->getFloatValue();
352 }
353
354 AtomicString CSSToStyleMap::mapAnimationName(CSSValue* value)
355 {
356     if (value->isInitialValue())
357         return CSSAnimationData::initialName();
358     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
359     if (primitiveValue->getValueID() == CSSValueNone)
360         return CSSAnimationData::initialName();
361     return AtomicString(primitiveValue->getStringValue());
362 }
363
364 EAnimPlayState CSSToStyleMap::mapAnimationPlayState(CSSValue* value)
365 {
366     if (value->isInitialValue())
367         return CSSAnimationData::initialPlayState();
368     if (toCSSPrimitiveValue(value)->getValueID() == CSSValuePaused)
369         return AnimPlayStatePaused;
370     ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueRunning);
371     return AnimPlayStatePlaying;
372 }
373
374 CSSTransitionData::TransitionProperty CSSToStyleMap::mapAnimationProperty(CSSValue* value)
375 {
376     if (value->isInitialValue())
377         return CSSTransitionData::initialProperty();
378     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
379     if (primitiveValue->isString())
380         return CSSTransitionData::TransitionProperty(primitiveValue->getStringValue());
381     if (primitiveValue->getValueID() == CSSValueAll)
382         return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionAll);
383     if (primitiveValue->getValueID() == CSSValueNone)
384         return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionNone);
385     return CSSTransitionData::TransitionProperty(primitiveValue->getPropertyID());
386 }
387
388 PassRefPtr<TimingFunction> CSSToStyleMap::mapAnimationTimingFunction(CSSValue* value, bool allowStepMiddle)
389 {
390     // FIXME: We should probably only call into this function with a valid
391     // single timing function value which isn't initial or inherit. We can
392     // currently get into here with initial since the parser expands unset
393     // properties in shorthands to initial.
394
395     if (value->isPrimitiveValue()) {
396         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
397         switch (primitiveValue->getValueID()) {
398         case CSSValueLinear:
399             return LinearTimingFunction::shared();
400         case CSSValueEase:
401             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease);
402         case CSSValueEaseIn:
403             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
404         case CSSValueEaseOut:
405             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut);
406         case CSSValueEaseInOut:
407             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut);
408         case CSSValueStepStart:
409             return StepsTimingFunction::preset(StepsTimingFunction::Start);
410         case CSSValueStepMiddle:
411             if (allowStepMiddle)
412                 return StepsTimingFunction::preset(StepsTimingFunction::Middle);
413             return CSSTimingData::initialTimingFunction();
414         case CSSValueStepEnd:
415             return StepsTimingFunction::preset(StepsTimingFunction::End);
416         default:
417             ASSERT_NOT_REACHED();
418             return CSSTimingData::initialTimingFunction();
419         }
420     }
421
422     if (value->isCubicBezierTimingFunctionValue()) {
423         CSSCubicBezierTimingFunctionValue* cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value);
424         return CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2());
425     }
426
427     if (value->isInitialValue())
428         return CSSTimingData::initialTimingFunction();
429
430     CSSStepsTimingFunctionValue* stepsTimingFunction = toCSSStepsTimingFunctionValue(value);
431     if (stepsTimingFunction->stepAtPosition() == StepsTimingFunction::Middle && !allowStepMiddle)
432         return CSSTimingData::initialTimingFunction();
433     return StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtPosition());
434 }
435
436 void CSSToStyleMap::mapNinePieceImage(RenderStyle* mutableStyle, CSSPropertyID property, CSSValue* value, NinePieceImage& image)
437 {
438     // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
439     if (!value || !value->isValueList())
440         return;
441
442     // Retrieve the border image value.
443     CSSValueList* borderImage = toCSSValueList(value);
444
445     // Set the image (this kicks off the load).
446     CSSPropertyID imageProperty;
447     if (property == CSSPropertyWebkitBorderImage)
448         imageProperty = CSSPropertyBorderImageSource;
449     else if (property == CSSPropertyWebkitMaskBoxImage)
450         imageProperty = CSSPropertyWebkitMaskBoxImageSource;
451     else
452         imageProperty = property;
453
454     for (unsigned i = 0 ; i < borderImage->length() ; ++i) {
455         CSSValue* current = borderImage->item(i);
456
457         if (current->isImageValue() || current->isImageGeneratorValue() || current->isImageSetValue())
458             image.setImage(styleImage(imageProperty, current));
459         else if (current->isBorderImageSliceValue())
460             mapNinePieceImageSlice(current, image);
461         else if (current->isValueList()) {
462             CSSValueList* slashList = toCSSValueList(current);
463             size_t length = slashList->length();
464             // Map in the image slices.
465             if (length && slashList->item(0)->isBorderImageSliceValue())
466                 mapNinePieceImageSlice(slashList->item(0), image);
467
468             // Map in the border slices.
469             if (length > 1)
470                 image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1)));
471
472             // Map in the outset.
473             if (length > 2)
474                 image.setOutset(mapNinePieceImageQuad(slashList->item(2)));
475         } else if (current->isPrimitiveValue()) {
476             // Set the appropriate rules for stretch/round/repeat of the slices.
477             mapNinePieceImageRepeat(current, image);
478         }
479     }
480
481     if (property == CSSPropertyWebkitBorderImage) {
482         // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
483         // also set the border widths. We don't need to worry about percentages, since we don't even support
484         // those on real borders yet.
485         if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed())
486             mutableStyle->setBorderTopWidth(image.borderSlices().top().length().value());
487         if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed())
488             mutableStyle->setBorderRightWidth(image.borderSlices().right().length().value());
489         if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed())
490             mutableStyle->setBorderBottomWidth(image.borderSlices().bottom().length().value());
491         if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed())
492             mutableStyle->setBorderLeftWidth(image.borderSlices().left().length().value());
493     }
494 }
495
496 void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) const
497 {
498     if (!value || !value->isBorderImageSliceValue())
499         return;
500
501     // Retrieve the border image value.
502     CSSBorderImageSliceValue* borderImageSlice = toCSSBorderImageSliceValue(value);
503
504     // Set up a length box to represent our image slices.
505     LengthBox box;
506     Quad* slices = borderImageSlice->slices();
507     if (slices->top()->isPercentage())
508         box.m_top = Length(slices->top()->getDoubleValue(), Percent);
509     else
510         box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
511     if (slices->bottom()->isPercentage())
512         box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
513     else
514         box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
515     if (slices->left()->isPercentage())
516         box.m_left = Length(slices->left()->getDoubleValue(), Percent);
517     else
518         box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
519     if (slices->right()->isPercentage())
520         box.m_right = Length(slices->right()->getDoubleValue(), Percent);
521     else
522         box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
523     image.setImageSlices(box);
524
525     // Set our fill mode.
526     image.setFill(borderImageSlice->m_fill);
527 }
528
529 static BorderImageLength toBorderImageLength(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData)
530 {
531     if (value.isNumber())
532         return value.getDoubleValue();
533     if (value.isPercentage())
534         return Length(value.getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
535     if (value.getValueID() != CSSValueAuto)
536         return value.computeLength<Length>(conversionData);
537     return Length(Auto);
538 }
539
540 BorderImageLengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value) const
541 {
542     if (!value || !value->isPrimitiveValue())
543         return BorderImageLengthBox(Length(Auto));
544
545     Quad* slices = toCSSPrimitiveValue(value)->getQuadValue();
546
547     // Set up a border image length box to represent our image slices.
548     return BorderImageLengthBox(
549         toBorderImageLength(*slices->top(), cssToLengthConversionData()),
550         toBorderImageLength(*slices->right(), cssToLengthConversionData()),
551         toBorderImageLength(*slices->bottom(), cssToLengthConversionData()),
552         toBorderImageLength(*slices->left(), cssToLengthConversionData()));
553 }
554
555 void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) const
556 {
557     if (!value || !value->isPrimitiveValue())
558         return;
559
560     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
561     Pair* pair = primitiveValue->getPairValue();
562     if (!pair || !pair->first() || !pair->second())
563         return;
564
565     CSSValueID firstIdentifier = pair->first()->getValueID();
566     CSSValueID secondIdentifier = pair->second()->getValueID();
567
568     ENinePieceImageRule horizontalRule;
569     switch (firstIdentifier) {
570     case CSSValueStretch:
571         horizontalRule = StretchImageRule;
572         break;
573     case CSSValueRound:
574         horizontalRule = RoundImageRule;
575         break;
576     case CSSValueSpace:
577         horizontalRule = SpaceImageRule;
578         break;
579     default: // CSSValueRepeat
580         horizontalRule = RepeatImageRule;
581         break;
582     }
583     image.setHorizontalRule(horizontalRule);
584
585     ENinePieceImageRule verticalRule;
586     switch (secondIdentifier) {
587     case CSSValueStretch:
588         verticalRule = StretchImageRule;
589         break;
590     case CSSValueRound:
591         verticalRule = RoundImageRule;
592         break;
593     case CSSValueSpace:
594         verticalRule = SpaceImageRule;
595         break;
596     default: // CSSValueRepeat
597         verticalRule = RepeatImageRule;
598         break;
599     }
600     image.setVerticalRule(verticalRule);
601 }
602
603 };