• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  *     * Redistributions of source code must retain the above copyright
5  * notice, this list of conditions and the following disclaimer.
6  *     * Redistributions in binary form must reproduce the above
7  * copyright notice, this list of conditions and the following disclaimer
8  * in the documentation and/or other materials provided with the
9  * distribution.
10  *     * Neither the name of Google Inc. nor the names of its
11  * contributors may be used to endorse or promote products derived from
12  * this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "core/css/resolver/StyleBuilderConverter.h"
29 
30 #include "core/css/CSSFunctionValue.h"
31 #include "core/css/CSSGridLineNamesValue.h"
32 #include "core/css/CSSPrimitiveValueMappings.h"
33 #include "core/css/CSSReflectValue.h"
34 #include "core/css/CSSShadowValue.h"
35 #include "core/css/Pair.h"
36 #include "core/svg/SVGURIReference.h"
37 
38 namespace WebCore {
39 
40 namespace {
41 
convertGridTrackBreadth(const StyleResolverState & state,CSSPrimitiveValue * primitiveValue)42 static GridLength convertGridTrackBreadth(const StyleResolverState& state, CSSPrimitiveValue* primitiveValue)
43 {
44     if (primitiveValue->getValueID() == CSSValueMinContent)
45         return Length(MinContent);
46 
47     if (primitiveValue->getValueID() == CSSValueMaxContent)
48         return Length(MaxContent);
49 
50     // Fractional unit.
51     if (primitiveValue->isFlex())
52         return GridLength(primitiveValue->getDoubleValue());
53 
54     return primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
55 }
56 
57 } // namespace
58 
convertBoxReflect(StyleResolverState & state,CSSValue * value)59 PassRefPtr<StyleReflection> StyleBuilderConverter::convertBoxReflect(StyleResolverState& state, CSSValue* value)
60 {
61     if (value->isPrimitiveValue()) {
62         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
63         return RenderStyle::initialBoxReflect();
64     }
65 
66     CSSReflectValue* reflectValue = toCSSReflectValue(value);
67     RefPtr<StyleReflection> reflection = StyleReflection::create();
68     reflection->setDirection(*reflectValue->direction());
69     if (reflectValue->offset())
70         reflection->setOffset(reflectValue->offset()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()));
71     NinePieceImage mask;
72     mask.setMaskDefaults();
73     state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBoxReflect, reflectValue->mask(), mask);
74     reflection->setMask(mask);
75 
76     return reflection.release();
77 }
78 
convertFragmentIdentifier(StyleResolverState & state,CSSValue * value)79 AtomicString StyleBuilderConverter::convertFragmentIdentifier(StyleResolverState& state, CSSValue* value)
80 {
81     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
82     if (primitiveValue->isURI())
83         return SVGURIReference::fragmentIdentifierFromIRIString(primitiveValue->getStringValue(), state.element()->treeScope());
84     return nullAtom;
85 }
86 
convertGlyphOrientation(StyleResolverState &,CSSValue * value)87 EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolverState&, CSSValue* value)
88 {
89     if (!value->isPrimitiveValue())
90         return GO_0DEG;
91 
92     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
93     if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_DEG)
94         return GO_0DEG;
95 
96     float angle = fabsf(fmodf(primitiveValue->getFloatValue(), 360.0f));
97 
98     if (angle <= 45.0f || angle > 315.0f)
99         return GO_0DEG;
100     if (angle > 45.0f && angle <= 135.0f)
101         return GO_90DEG;
102     if (angle > 135.0f && angle <= 225.0f)
103         return GO_180DEG;
104     return GO_270DEG;
105 }
106 
convertGridPosition(StyleResolverState &,CSSValue * value)107 GridPosition StyleBuilderConverter::convertGridPosition(StyleResolverState&, CSSValue* value)
108 {
109     // We accept the specification's grammar:
110     // 'auto' | [ <integer> || <custom-ident> ] | [ span && [ <integer> || <custom-ident> ] ] | <custom-ident>
111 
112     GridPosition position;
113 
114     if (value->isPrimitiveValue()) {
115         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
116         // We translate <custom-ident> to <string> during parsing as it
117         // makes handling it more simple.
118         if (primitiveValue->isString()) {
119             position.setNamedGridArea(primitiveValue->getStringValue());
120             return position;
121         }
122 
123         ASSERT(primitiveValue->getValueID() == CSSValueAuto);
124         return position;
125     }
126 
127     CSSValueList* values = toCSSValueList(value);
128     ASSERT(values->length());
129 
130     bool isSpanPosition = false;
131     // The specification makes the <integer> optional, in which case it default to '1'.
132     int gridLineNumber = 1;
133     String gridLineName;
134 
135     CSSValueListIterator it = values;
136     CSSPrimitiveValue* currentValue = toCSSPrimitiveValue(it.value());
137     if (currentValue->getValueID() == CSSValueSpan) {
138         isSpanPosition = true;
139         it.advance();
140         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
141     }
142 
143     if (currentValue && currentValue->isNumber()) {
144         gridLineNumber = currentValue->getIntValue();
145         it.advance();
146         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
147     }
148 
149     if (currentValue && currentValue->isString()) {
150         gridLineName = currentValue->getStringValue();
151         it.advance();
152     }
153 
154     ASSERT(!it.hasMore());
155     if (isSpanPosition)
156         position.setSpanPosition(gridLineNumber, gridLineName);
157     else
158         position.setExplicitPosition(gridLineNumber, gridLineName);
159 
160     return position;
161 }
162 
convertGridTrackSize(StyleResolverState & state,CSSValue * value)163 GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolverState& state, CSSValue* value)
164 {
165     if (value->isPrimitiveValue())
166         return GridTrackSize(convertGridTrackBreadth(state, toCSSPrimitiveValue(value)));
167 
168     CSSFunctionValue* minmaxFunction = toCSSFunctionValue(value);
169     CSSValueList* arguments = minmaxFunction->arguments();
170     ASSERT_WITH_SECURITY_IMPLICATION(arguments->length() == 2);
171     GridLength minTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->itemWithoutBoundsCheck(0))));
172     GridLength maxTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->itemWithoutBoundsCheck(1))));
173     return GridTrackSize(minTrackBreadth, maxTrackBreadth);
174 }
175 
convertGridTrackList(CSSValue * value,Vector<GridTrackSize> & trackSizes,NamedGridLinesMap & namedGridLines,OrderedNamedGridLines & orderedNamedGridLines,StyleResolverState & state)176 bool StyleBuilderConverter::convertGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, StyleResolverState& state)
177 {
178     // Handle 'none'.
179     if (value->isPrimitiveValue()) {
180         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
181         return primitiveValue->getValueID() == CSSValueNone;
182     }
183 
184     if (!value->isValueList())
185         return false;
186 
187     size_t currentNamedGridLine = 0;
188     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
189         CSSValue* currValue = i.value();
190         if (currValue->isGridLineNamesValue()) {
191             CSSGridLineNamesValue* lineNamesValue = toCSSGridLineNamesValue(currValue);
192             for (CSSValueListIterator j = lineNamesValue; j.hasMore(); j.advance()) {
193                 String namedGridLine = toCSSPrimitiveValue(j.value())->getStringValue();
194                 NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>());
195                 result.storedValue->value.append(currentNamedGridLine);
196                 OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
197                 orderedInsertionResult.storedValue->value.append(namedGridLine);
198             }
199             continue;
200         }
201 
202         ++currentNamedGridLine;
203         trackSizes.append(convertGridTrackSize(state, currValue));
204     }
205 
206     // The parser should have rejected any <track-list> without any <track-size> as
207     // this is not conformant to the syntax.
208     ASSERT(!trackSizes.isEmpty());
209     return true;
210 }
211 
createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap & namedGridAreas,NamedGridLinesMap & namedGridLines,GridTrackSizingDirection direction)212 void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
213 {
214     NamedGridAreaMap::const_iterator end = namedGridAreas.end();
215     for (NamedGridAreaMap::const_iterator it = namedGridAreas.begin(); it != end; ++it) {
216         GridSpan areaSpan = direction == ForRows ? it->value.rows : it->value.columns;
217         {
218             NamedGridLinesMap::AddResult startResult = namedGridLines.add(it->key + "-start", Vector<size_t>());
219             startResult.storedValue->value.append(areaSpan.resolvedInitialPosition.toInt());
220             std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end());
221         }
222         {
223             NamedGridLinesMap::AddResult endResult = namedGridLines.add(it->key + "-end", Vector<size_t>());
224             endResult.storedValue->value.append(areaSpan.resolvedFinalPosition.toInt() + 1);
225             std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end());
226         }
227     }
228 }
229 
convertLength(StyleResolverState & state,CSSValue * value)230 Length StyleBuilderConverter::convertLength(StyleResolverState& state, CSSValue* value)
231 {
232     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
233     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
234     result.setQuirk(primitiveValue->isQuirkValue());
235     return result;
236 }
237 
convertLengthOrAuto(StyleResolverState & state,CSSValue * value)238 Length StyleBuilderConverter::convertLengthOrAuto(StyleResolverState& state, CSSValue* value)
239 {
240     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
241     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
242     result.setQuirk(primitiveValue->isQuirkValue());
243     return result;
244 }
245 
convertLengthSizing(StyleResolverState & state,CSSValue * value)246 Length StyleBuilderConverter::convertLengthSizing(StyleResolverState& state, CSSValue* value)
247 {
248     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
249     switch (primitiveValue->getValueID()) {
250     case CSSValueInvalid:
251         return convertLength(state, value);
252     case CSSValueIntrinsic:
253         return Length(Intrinsic);
254     case CSSValueMinIntrinsic:
255         return Length(MinIntrinsic);
256     case CSSValueWebkitMinContent:
257         return Length(MinContent);
258     case CSSValueWebkitMaxContent:
259         return Length(MaxContent);
260     case CSSValueWebkitFillAvailable:
261         return Length(FillAvailable);
262     case CSSValueWebkitFitContent:
263         return Length(FitContent);
264     case CSSValueAuto:
265         return Length(Auto);
266     default:
267         ASSERT_NOT_REACHED();
268         return Length();
269     }
270 }
271 
convertLengthMaxSizing(StyleResolverState & state,CSSValue * value)272 Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolverState& state, CSSValue* value)
273 {
274     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
275     if (primitiveValue->getValueID() == CSSValueNone)
276         return Length(Undefined);
277     return convertLengthSizing(state, value);
278 }
279 
convertLengthPoint(StyleResolverState & state,CSSValue * value)280 LengthPoint StyleBuilderConverter::convertLengthPoint(StyleResolverState& state, CSSValue* value)
281 {
282     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
283     Pair* pair = primitiveValue->getPairValue();
284     Length x = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
285     Length y = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
286     return LengthPoint(x, y);
287 }
288 
convertLineBoxContain(StyleResolverState &,CSSValue * value)289 LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolverState&, CSSValue* value)
290 {
291     if (value->isPrimitiveValue()) {
292         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
293         return LineBoxContainNone;
294     }
295 
296     return toCSSLineBoxContainValue(value)->value();
297 }
298 
convertNumberOrPercentage(StyleResolverState & state,CSSValue * value)299 float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state, CSSValue* value)
300 {
301     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
302     ASSERT(primitiveValue->isNumber() || primitiveValue->isPercentage());
303     if (primitiveValue->isNumber())
304         return primitiveValue->getFloatValue();
305     return primitiveValue->getFloatValue() / 100.0f;
306 }
307 
convertPaintOrder(StyleResolverState &,CSSValue * cssPaintOrder)308 EPaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolverState&, CSSValue* cssPaintOrder)
309 {
310     if (cssPaintOrder->isValueList()) {
311         int paintOrder = 0;
312         CSSValueListInspector iter(cssPaintOrder);
313         for (size_t i = 0; i < iter.length(); i++) {
314             CSSPrimitiveValue* value = toCSSPrimitiveValue(iter.item(i));
315 
316             EPaintOrderType paintOrderType = PT_NONE;
317             switch (value->getValueID()) {
318             case CSSValueFill:
319                 paintOrderType = PT_FILL;
320                 break;
321             case CSSValueStroke:
322                 paintOrderType = PT_STROKE;
323                 break;
324             case CSSValueMarkers:
325                 paintOrderType = PT_MARKERS;
326                 break;
327             default:
328                 ASSERT_NOT_REACHED();
329                 break;
330             }
331 
332             paintOrder |= (paintOrderType << kPaintOrderBitwidth*i);
333         }
334         return (EPaintOrder)paintOrder;
335     }
336 
337     return PO_NORMAL;
338 }
339 
convertQuotes(StyleResolverState &,CSSValue * value)340 PassRefPtr<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolverState&, CSSValue* value)
341 {
342     if (value->isValueList()) {
343         CSSValueList* list = toCSSValueList(value);
344         RefPtr<QuotesData> quotes = QuotesData::create();
345         for (size_t i = 0; i < list->length(); i += 2) {
346             CSSValue* first = list->itemWithoutBoundsCheck(i);
347             // item() returns null if out of bounds so this is safe.
348             CSSValue* second = list->item(i + 1);
349             if (!second)
350                 continue;
351             String startQuote = toCSSPrimitiveValue(first)->getStringValue();
352             String endQuote = toCSSPrimitiveValue(second)->getStringValue();
353             quotes->addPair(std::make_pair(startQuote, endQuote));
354         }
355         return quotes.release();
356     }
357     // FIXME: We should assert we're a primitive value with valueID = CSSValueNone
358     return QuotesData::create();
359 }
360 
convertRadius(StyleResolverState & state,CSSValue * value)361 LengthSize StyleBuilderConverter::convertRadius(StyleResolverState& state, CSSValue* value)
362 {
363     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
364     Pair* pair = primitiveValue->getPairValue();
365     Length radiusWidth = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
366     Length radiusHeight = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
367     float width = radiusWidth.value();
368     float height = radiusHeight.value();
369     ASSERT(width >= 0 && height >= 0);
370     if (width <= 0 || height <= 0)
371         return LengthSize(Length(0, Fixed), Length(0, Fixed));
372     return LengthSize(radiusWidth, radiusHeight);
373 }
374 
convertShadow(StyleResolverState & state,CSSValue * value)375 PassRefPtr<ShadowList> StyleBuilderConverter::convertShadow(StyleResolverState& state, CSSValue* value)
376 {
377     if (value->isPrimitiveValue()) {
378         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
379         return PassRefPtr<ShadowList>();
380     }
381 
382     const CSSValueList* valueList = toCSSValueList(value);
383     size_t shadowCount = valueList->length();
384     ShadowDataVector shadows;
385     for (size_t i = 0; i < shadowCount; ++i) {
386         const CSSShadowValue* item = toCSSShadowValue(valueList->item(i));
387         float x = item->x->computeLength<float>(state.cssToLengthConversionData());
388         float y = item->y->computeLength<float>(state.cssToLengthConversionData());
389         float blur = item->blur ? item->blur->computeLength<float>(state.cssToLengthConversionData()) : 0;
390         float spread = item->spread ? item->spread->computeLength<float>(state.cssToLengthConversionData()) : 0;
391         ShadowStyle shadowStyle = item->style && item->style->getValueID() == CSSValueInset ? Inset : Normal;
392         Color color;
393         if (item->color)
394             color = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color());
395         else
396             color = state.style()->color();
397         shadows.append(ShadowData(FloatPoint(x, y), blur, spread, shadowStyle, color));
398     }
399     return ShadowList::adopt(shadows);
400 }
401 
convertSpacing(StyleResolverState & state,CSSValue * value)402 float StyleBuilderConverter::convertSpacing(StyleResolverState& state, CSSValue* value)
403 {
404     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
405     if (primitiveValue->getValueID() == CSSValueNormal)
406         return 0;
407     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
408 }
409 
convertStrokeDasharray(StyleResolverState &,CSSValue * value)410 PassRefPtr<SVGLengthList> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState&, CSSValue* value)
411 {
412     if (!value->isValueList()) {
413         return SVGRenderStyle::initialStrokeDashArray();
414     }
415 
416     CSSValueList* dashes = toCSSValueList(value);
417 
418     RefPtr<SVGLengthList> array = SVGLengthList::create();
419     size_t length = dashes->length();
420     for (size_t i = 0; i < length; ++i) {
421         CSSValue* currValue = dashes->itemWithoutBoundsCheck(i);
422         if (!currValue->isPrimitiveValue())
423             continue;
424 
425         CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->itemWithoutBoundsCheck(i));
426         array->append(SVGLength::fromCSSPrimitiveValue(dash));
427     }
428 
429     return array.release();
430 }
431 
convertSVGColor(StyleResolverState & state,CSSValue * value)432 Color StyleBuilderConverter::convertSVGColor(StyleResolverState& state, CSSValue* value)
433 {
434     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
435     if (primitiveValue->isRGBColor())
436         return primitiveValue->getRGBA32Value();
437     ASSERT(primitiveValue->getValueID() == CSSValueCurrentcolor);
438     return state.style()->color();
439 }
440 
convertSVGLength(StyleResolverState &,CSSValue * value)441 PassRefPtr<SVGLength> StyleBuilderConverter::convertSVGLength(StyleResolverState&, CSSValue* value)
442 {
443     return SVGLength::fromCSSPrimitiveValue(toCSSPrimitiveValue(value));
444 }
445 
convertTextStrokeWidth(StyleResolverState & state,CSSValue * value)446 float StyleBuilderConverter::convertTextStrokeWidth(StyleResolverState& state, CSSValue* value)
447 {
448     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
449     if (primitiveValue->getValueID()) {
450         float multiplier = convertLineWidth<float>(state, value);
451         return CSSPrimitiveValue::create(multiplier / 48, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.cssToLengthConversionData());
452     }
453     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
454 }
455 
456 } // namespace WebCore
457