Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: Source/core/css/MediaList.cpp

Issue 15094019: Fixing inconsistency with Media Query append/deleteMedium. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org) 2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2006, 2010, 2012 Apple Inc. All rights reserved. 3 * Copyright (C) 2004, 2006, 2010, 2012 Apple Inc. All rights reserved.
4 * 4 *
5 * This library is free software; you can redistribute it and/or 5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public 6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either 7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version. 8 * version 2 of the License, or (at your option) any later version.
9 * 9 *
10 * This library is distributed in the hope that it will be useful, 10 * This library is distributed in the hope that it will be useful,
(...skipping 17 matching lines...) Expand all
28 #include "core/dom/Document.h" 28 #include "core/dom/Document.h"
29 #include "core/dom/ExceptionCode.h" 29 #include "core/dom/ExceptionCode.h"
30 #include "core/dom/WebCoreMemoryInstrumentation.h" 30 #include "core/dom/WebCoreMemoryInstrumentation.h"
31 #include "core/page/DOMWindow.h" 31 #include "core/page/DOMWindow.h"
32 #include "wtf/MemoryInstrumentationVector.h" 32 #include "wtf/MemoryInstrumentationVector.h"
33 #include "wtf/text/StringBuilder.h" 33 #include "wtf/text/StringBuilder.h"
34 34
35 namespace WebCore { 35 namespace WebCore {
36 36
37 /* MediaList is used to store 3 types of media related entities which mean the s ame: 37 /* MediaList is used to store 3 types of media related entities which mean the s ame:
38 *
38 * Media Queries, Media Types and Media Descriptors. 39 * Media Queries, Media Types and Media Descriptors.
39 * Currently MediaList always tries to parse media queries and if parsing fails, 40 *
40 * tries to fallback to Media Descriptors if m_fallbackToDescriptor flag is set.
41 * Slight problem with syntax error handling: 41 * Slight problem with syntax error handling:
42 * CSS 2.1 Spec (http://www.w3.org/TR/CSS21/media.html) 42 * CSS 2.1 Spec (http://www.w3.org/TR/CSS21/media.html)
43 * specifies that failing media type parsing is a syntax error 43 * specifies that failing media type parsing is a syntax error
44 * CSS 3 Media Queries Spec (http://www.w3.org/TR/css3-mediaqueries/) 44 * CSS 3 Media Queries Spec (http://www.w3.org/TR/css3-mediaqueries/)
45 * specifies that failing media query is a syntax error 45 * specifies that failing media query is a syntax error
46 * HTML 4.01 spec (http://www.w3.org/TR/REC-html40/present/styles.html#adef-medi a) 46 * HTML 4.01 spec (http://www.w3.org/TR/REC-html40/present/styles.html#adef-medi a)
47 * specifies that Media Descriptors should be parsed with forward-compatible syn tax 47 * specifies that Media Descriptors should be parsed with forward-compatible syn tax
48 * DOM Level 2 Style Sheet spec (http://www.w3.org/TR/DOM-Level-2-Style/) 48 * DOM Level 2 Style Sheet spec (http://www.w3.org/TR/DOM-Level-2-Style/)
49 * talks about MediaList.mediaText and refers 49 * talks about MediaList.mediaText and refers
50 * - to Media Descriptors of HTML 4.0 in context of StyleSheet 50 * - to Media Descriptors of HTML 4.0 in context of StyleSheet
51 * - to Media Types of CSS 2.0 in context of CSSMediaRule and CSSImportRule 51 * - to Media Types of CSS 2.0 in context of CSSMediaRule and CSSImportRule
52 * 52 *
53 * These facts create situation where same (illegal) media specification may res ult in 53 * These facts create situation where same (illegal) media specification may res ult in
54 * different parses depending on whether it is media attr of style element or pa rt of 54 * different parses depending on whether it is media attr of style element or pa rt of
55 * css @media rule. 55 * css @media rule.
56 * <style media="screen and resolution > 40dpi"> ..</style> will be enabled on s creen devices where as 56 * <style media="screen and resolution > 40dpi"> ..</style> will be enabled on s creen devices where as
57 * @media screen and resolution > 40dpi {..} will not. 57 * @media screen and resolution > 40dpi {..} will not.
58 * This gets more counter-intuitive in JavaScript: 58 * This gets more counter-intuitive in JavaScript:
59 * document.styleSheets[0].media.mediaText = "screen and resolution > 40dpi" wil l be ok and 59 * document.styleSheets[0].media.mediaText = "screen and resolution > 40dpi" wil l be ok and
60 * enabled, while 60 * enabled, while
61 * document.styleSheets[0].cssRules[0].media.mediaText = "screen and resolution > 40dpi" will 61 * document.styleSheets[0].cssRules[0].media.mediaText = "screen and resolution > 40dpi" will
62 * throw SYNTAX_ERR exception. 62 * throw SYNTAX_ERR exception.
63 */ 63 */
64 64
65 MediaQuerySet::MediaQuerySet() 65 MediaQuerySet::MediaQuerySet()
66 : m_fallbackToDescriptor(false) 66 : m_parserMode(MediaQueryNormalMode)
67 , m_lastLine(0) 67 , m_lastLine(0)
68 { 68 {
69 } 69 }
70 70
71 MediaQuerySet::MediaQuerySet(const String& mediaString, bool fallbackToDescripto r) 71 MediaQuerySet::MediaQuerySet(const String& mediaString, MediaQueryParserMode mod e)
72 : m_fallbackToDescriptor(fallbackToDescriptor) 72 : m_parserMode(mode)
73 , m_lastLine(0) 73 , m_lastLine(0)
74 { 74 {
75 bool success = parse(mediaString); 75 set(mediaString);
76 // FIXME: parsing can fail. The problem with failing constructor is that
77 // we would need additional flag saying MediaList is not valid
78 // Parse can fail only when fallbackToDescriptor == false, i.e when HTML4 me dia descriptor
79 // forward-compatible syntax is not in use.
80 // DOMImplementationCSS seems to mandate that media descriptors are used
81 // for both html and svg, even though svg:style doesn't use media descriptor s
82 // Currently the only places where parsing can fail are
83 // creating <svg:style>, creating css media / import rules from js
84
85 // FIXME: This doesn't make much sense.
86 if (!success)
87 parse("invalid");
88 } 76 }
89 77
90 MediaQuerySet::MediaQuerySet(const MediaQuerySet& o) 78 MediaQuerySet::MediaQuerySet(const MediaQuerySet& o)
91 : RefCounted<MediaQuerySet>() 79 : RefCounted<MediaQuerySet>()
92 , m_fallbackToDescriptor(o.m_fallbackToDescriptor) 80 , m_parserMode(o.m_parserMode)
93 , m_lastLine(o.m_lastLine) 81 , m_lastLine(o.m_lastLine)
94 , m_queries(o.m_queries.size()) 82 , m_queries(o.m_queries.size())
95 { 83 {
96 for (unsigned i = 0; i < m_queries.size(); ++i) 84 for (unsigned i = 0; i < m_queries.size(); ++i)
97 m_queries[i] = o.m_queries[i]->copy(); 85 m_queries[i] = o.m_queries[i]->copy();
98 } 86 }
99 87
100 MediaQuerySet::~MediaQuerySet() 88 MediaQuerySet::~MediaQuerySet()
101 { 89 {
102 } 90 }
103 91
104 static String parseMediaDescriptor(const String& string) 92 static String parseMediaDescriptor(const String& string)
105 { 93 {
106 // http://www.w3.org/TR/REC-html40/types.html#type-media-descriptors 94 // http://www.w3.org/TR/REC-html40/types.html#type-media-descriptors
107 // "Each entry is truncated just before the first character that isn't a 95 // "Each entry is truncated just before the first character that isn't a
108 // US ASCII letter [a-zA-Z] (ISO 10646 hex 41-5a, 61-7a), digit [0-9] (hex 3 0-39), 96 // US ASCII letter [a-zA-Z] (ISO 10646 hex 41-5a, 61-7a), digit [0-9] (hex 3 0-39),
109 // or hyphen (hex 2d)." 97 // or hyphen (hex 2d)."
110 unsigned length = string.length(); 98 unsigned length = string.length();
111 unsigned i = 0; 99 unsigned i = 0;
112 for (; i < length; ++i) { 100 for (; i < length; ++i) {
113 unsigned short c = string[i]; 101 unsigned short c = string[i];
114 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '1' && c <= '9') || (c == '-'))) 102 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '1' && c <= '9') || (c == '-')))
115 break; 103 break;
116 } 104 }
117 return string.left(i); 105 return string.left(i);
118 } 106 }
119 107
120 PassOwnPtr<MediaQuery> MediaQuerySet::parseMediaQuery(const String& queryString) 108 PassOwnPtr<MediaQuery> MediaQuerySet::parseMediaQuery(const String& queryString, MediaQueryParserMode mode)
121 { 109 {
122 CSSParser parser(CSSStrictMode); 110 CSSParser parser(CSSStrictMode);
123 OwnPtr<MediaQuery> parsedQuery = parser.parseMediaQuery(queryString); 111 OwnPtr<MediaQuery> parsedQuery = parser.parseMediaQuery(queryString);
124 112
125 if (parsedQuery) 113 if (parsedQuery)
126 return parsedQuery.release(); 114 return parsedQuery.release();
127 115
128 if (m_fallbackToDescriptor) { 116 switch (mode) {
117 case MediaQueryForwardCompatibleSyntaxMode: {
129 String medium = parseMediaDescriptor(queryString); 118 String medium = parseMediaDescriptor(queryString);
130 if (!medium.isNull()) 119 if (!medium.isNull())
131 return adoptPtr(new MediaQuery(MediaQuery::None, medium, nullptr)); 120 return adoptPtr(new MediaQuery(MediaQuery::None, medium, nullptr));
apavlov 2013/05/29 15:44:36 Should you add something like // Fall through. aft
kenneth.r.christiansen 2013/05/29 15:52:56 I actually had that :-) Let me readd that
132 } 121 }
133 122 case MediaQueryNormalMode:
134 return adoptPtr(new MediaQuery(MediaQuery::None, "not all", nullptr)); 123 return adoptPtr(new MediaQuery(MediaQuery::None, "not all", nullptr));
124 case MediaQueryStrictMode:
125 default:
apavlov 2013/05/29 15:44:36 Should we guard ourselves against the default-case
kenneth.r.christiansen 2013/05/29 15:52:56 Fine with me
126 return nullptr;
127 }
135 } 128 }
136 129
137 bool MediaQuerySet::parse(const String& mediaString) 130 void MediaQuerySet::parseMediaQueryList(const String& mediaString, MediaQueryPar serMode mode, Vector<OwnPtr<MediaQuery> >& result)
138 { 131 {
139 if (mediaString.isEmpty()) { 132 if (mediaString.isEmpty()) {
140 m_queries.clear(); 133 result.clear();
141 return true; 134 return;
142 } 135 }
143 136
144 Vector<String> list; 137 Vector<String> list;
145 // FIXME: This is too simple as it shouldn't split when the ',' is inside 138 // FIXME: This is too simple as it shouldn't split when the ',' is inside
146 // other allowed matching pairs such as (), [], {}, "", and ''. 139 // other allowed matching pairs such as (), [], {}, "", and ''.
147 mediaString.split(',', /* allowEmptyEntries */ true, list); 140 mediaString.split(',', /* allowEmptyEntries */ true, list);
148 141
149 Vector<OwnPtr<MediaQuery> > result;
150 result.reserveInitialCapacity(list.size()); 142 result.reserveInitialCapacity(list.size());
151 143
152 for (unsigned i = 0; i < list.size(); ++i) { 144 for (unsigned i = 0; i < list.size(); ++i) {
153 String queryString = list[i].stripWhiteSpace(); 145 String queryString = list[i].stripWhiteSpace();
154 if (OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryString)) 146 OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryString, mode);
147 if (parsedQuery)
155 result.uncheckedAppend(parsedQuery.release()); 148 result.uncheckedAppend(parsedQuery.release());
156 } 149 }
150 }
157 151
152 bool MediaQuerySet::set(const String& mediaString)
153 {
154 Vector<OwnPtr<MediaQuery> > result;
155 parseMediaQueryList(mediaString, m_parserMode, result);
158 m_queries.swap(result); 156 m_queries.swap(result);
159 return true; 157 return true;
160 } 158 }
161 159
162 bool MediaQuerySet::add(const String& queryString) 160 bool MediaQuerySet::add(const String& queryString)
163 { 161 {
164 if (OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryString)) { 162 // To parse a media query for a given string means to follow the parse
165 m_queries.append(parsedQuery.release()); 163 // a media query list steps and return null if more than one media query
apavlov 2013/05/29 15:44:36 Should the "parse a media query list" be quoted so
kenneth.r.christiansen 2013/05/29 15:52:56 Just quotes around that? That is fine with me.
164 // is returned or a media query if a single media query is returned.
165 Vector<OwnPtr<MediaQuery> > queries;
166 parseMediaQueryList(queryString, MediaQueryStrictMode, queries);
167
168 // If "null", terminate these steps.
apavlov 2013/05/29 15:44:36 Can it be more than 1, as opposed to 0?
kenneth.r.christiansen 2013/05/29 15:52:56 No, it cannot according to the spec. It has to be
169 if (queries.size() != 1)
166 return true; 170 return true;
171
172 OwnPtr<MediaQuery> newQuery = queries[0].release();
173 ASSERT(newQuery);
174
175 // If comparing with any of the media queries in the collection of media
176 // queries returns true terminate these steps.
177 for (size_t i = 0; i < m_queries.size(); ++i) {
178 MediaQuery* query = m_queries[i].get();
179 if (*query == *newQuery)
180 return true;
167 } 181 }
168 return false; 182
183 m_queries.append(newQuery.release());
184 return true;
169 } 185 }
170 186
171 bool MediaQuerySet::remove(const String& queryStringToRemove) 187 bool MediaQuerySet::remove(const String& queryStringToRemove)
172 { 188 {
173 OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryStringToRemove); 189 // To parse a media query for a given string means to follow the parse
apavlov 2013/05/29 15:44:36 Ditto for quoting
174 if (!parsedQuery) 190 // a media query list steps and return null if more than one media query
175 return false; 191 // is returned or a media query if a single media query is returned.
192 Vector<OwnPtr<MediaQuery> > queries;
193 parseMediaQueryList(queryStringToRemove, MediaQueryStrictMode, queries);
176 194
195 // If "null", terminate these steps.
apavlov 2013/05/29 15:44:36 Ditto for the comment
kenneth.r.christiansen 2013/05/29 15:52:56 Suggestions for the comments?
196 if (queries.size() != 1)
197 return true;
198
199 OwnPtr<MediaQuery> newQuery = queries[0].release();
200 ASSERT(newQuery);
201
202 // Remove any media query from the collection of media queries for which
203 // comparing the media query with m returns true.
apavlov 2013/05/29 15:44:36 What is "m"?
kenneth.r.christiansen 2013/05/29 15:52:56 Copy paste from the algorithm, forgot to remove th
204 bool found = false;
177 for (size_t i = 0; i < m_queries.size(); ++i) { 205 for (size_t i = 0; i < m_queries.size(); ++i) {
178 MediaQuery* query = m_queries[i].get(); 206 MediaQuery* query = m_queries[i].get();
179 if (*query == *parsedQuery) { 207 if (*query == *newQuery) {
180 m_queries.remove(i); 208 m_queries.remove(i);
181 return true; 209 --i;
210 found = true;
182 } 211 }
183 } 212 }
184 return false; 213
214 return found;
185 } 215 }
186 216
187 void MediaQuerySet::addMediaQuery(PassOwnPtr<MediaQuery> mediaQuery) 217 void MediaQuerySet::addMediaQuery(PassOwnPtr<MediaQuery> mediaQuery)
188 { 218 {
189 m_queries.append(mediaQuery); 219 m_queries.append(mediaQuery);
190 } 220 }
191 221
192 String MediaQuerySet::mediaText() const 222 String MediaQuerySet::mediaText() const
193 { 223 {
194 StringBuilder text; 224 StringBuilder text;
(...skipping 26 matching lines...) Expand all
221 : m_mediaQueries(mediaQueries) 251 : m_mediaQueries(mediaQueries)
222 , m_parentStyleSheet(0) 252 , m_parentStyleSheet(0)
223 , m_parentRule(parentRule) 253 , m_parentRule(parentRule)
224 { 254 {
225 } 255 }
226 256
227 MediaList::~MediaList() 257 MediaList::~MediaList()
228 { 258 {
229 } 259 }
230 260
231 void MediaList::setMediaText(const String& value, ExceptionCode& ec) 261 void MediaList::setMediaText(const String& value)
232 { 262 {
233 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); 263 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule);
234 264
235 bool success = m_mediaQueries->parse(value); 265 m_mediaQueries->set(value);
236 if (!success) { 266
237 ec = SYNTAX_ERR;
238 return;
239 }
240 if (m_parentStyleSheet) 267 if (m_parentStyleSheet)
241 m_parentStyleSheet->didMutate(); 268 m_parentStyleSheet->didMutate();
242 } 269 }
243 270
244 String MediaList::item(unsigned index) const 271 String MediaList::item(unsigned index) const
245 { 272 {
246 const Vector<OwnPtr<MediaQuery> >& queries = m_mediaQueries->queryVector(); 273 const Vector<OwnPtr<MediaQuery> >& queries = m_mediaQueries->queryVector();
247 if (index < queries.size()) 274 if (index < queries.size())
248 return queries[index]->cssText(); 275 return queries[index]->cssText();
249 return String(); 276 return String();
(...skipping 11 matching lines...) Expand all
261 if (m_parentStyleSheet) 288 if (m_parentStyleSheet)
262 m_parentStyleSheet->didMutate(); 289 m_parentStyleSheet->didMutate();
263 } 290 }
264 291
265 void MediaList::appendMedium(const String& medium, ExceptionCode& ec) 292 void MediaList::appendMedium(const String& medium, ExceptionCode& ec)
266 { 293 {
267 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); 294 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule);
268 295
269 bool success = m_mediaQueries->add(medium); 296 bool success = m_mediaQueries->add(medium);
270 if (!success) { 297 if (!success) {
271 // FIXME: Should this really be INVALID_CHARACTER_ERR?
272 ec = INVALID_CHARACTER_ERR; 298 ec = INVALID_CHARACTER_ERR;
273 return; 299 return;
274 } 300 }
301
275 if (m_parentStyleSheet) 302 if (m_parentStyleSheet)
276 m_parentStyleSheet->didMutate(); 303 m_parentStyleSheet->didMutate();
277 } 304 }
278 305
279 void MediaList::reattach(MediaQuerySet* mediaQueries) 306 void MediaList::reattach(MediaQuerySet* mediaQueries)
280 { 307 {
281 ASSERT(mediaQueries); 308 ASSERT(mediaQueries);
282 m_mediaQueries = mediaQueries; 309 m_mediaQueries = mediaQueries;
283 } 310 }
284 311
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssV alue); 373 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssV alue);
347 if (primitiveValue->isDotsPerInch() || primitiveValue->isDot sPerCentimeter()) 374 if (primitiveValue->isDotsPerInch() || primitiveValue->isDot sPerCentimeter())
348 addResolutionWarningMessageToConsole(document, mediaQuer ySet->mediaText(), primitiveValue); 375 addResolutionWarningMessageToConsole(document, mediaQuer ySet->mediaText(), primitiveValue);
349 } 376 }
350 } 377 }
351 } 378 }
352 } 379 }
353 } 380 }
354 381
355 } 382 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698