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

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
« no previous file with comments | « Source/core/css/MediaList.h ('k') | Source/core/css/MediaList.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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));
121 // Fall throught.
apavlov 2013/05/30 09:49:56 typo: should be "through"
132 } 122 }
133 123 case MediaQueryNormalMode:
134 return adoptPtr(new MediaQuery(MediaQuery::None, "not all", nullptr)); 124 return adoptPtr(new MediaQuery(MediaQuery::None, "not all", nullptr));
125 case MediaQueryStrictMode:
126 break;
127 default:
128 ASSERT_NOT_REACHED();
129 break;
130 }
131 return nullptr;
135 } 132 }
136 133
137 bool MediaQuerySet::parse(const String& mediaString) 134 void MediaQuerySet::parseMediaQueryList(const String& mediaString, MediaQueryPar serMode mode, Vector<OwnPtr<MediaQuery> >& result)
138 { 135 {
139 if (mediaString.isEmpty()) { 136 if (mediaString.isEmpty()) {
140 m_queries.clear(); 137 result.clear();
141 return true; 138 return;
142 } 139 }
143 140
144 Vector<String> list; 141 Vector<String> list;
145 // FIXME: This is too simple as it shouldn't split when the ',' is inside 142 // FIXME: This is too simple as it shouldn't split when the ',' is inside
146 // other allowed matching pairs such as (), [], {}, "", and ''. 143 // other allowed matching pairs such as (), [], {}, "", and ''.
147 mediaString.split(',', /* allowEmptyEntries */ true, list); 144 mediaString.split(',', /* allowEmptyEntries */ true, list);
148 145
149 Vector<OwnPtr<MediaQuery> > result;
150 result.reserveInitialCapacity(list.size()); 146 result.reserveInitialCapacity(list.size());
151 147
152 for (unsigned i = 0; i < list.size(); ++i) { 148 for (unsigned i = 0; i < list.size(); ++i) {
153 String queryString = list[i].stripWhiteSpace(); 149 String queryString = list[i].stripWhiteSpace();
154 if (OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryString)) 150 OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryString, mode);
151 if (parsedQuery)
155 result.uncheckedAppend(parsedQuery.release()); 152 result.uncheckedAppend(parsedQuery.release());
156 } 153 }
154 }
157 155
156 bool MediaQuerySet::set(const String& mediaString)
157 {
158 Vector<OwnPtr<MediaQuery> > result;
159 parseMediaQueryList(mediaString, parserMode(), result);
158 m_queries.swap(result); 160 m_queries.swap(result);
159 return true; 161 return true;
160 } 162 }
161 163
162 bool MediaQuerySet::add(const String& queryString) 164 bool MediaQuerySet::add(const String& queryString)
163 { 165 {
164 if (OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryString)) { 166 // To "parse a media query" for a given string means to follow "the parse
165 m_queries.append(parsedQuery.release()); 167 // a media query list" steps and return "null" if more than one media query
168 // is returned, or else the returned media query.
169 Vector<OwnPtr<MediaQuery> > queries;
170 parseMediaQueryList(queryString, MediaQueryStrictMode, queries);
171
172 // Only continue if exactly one media query is found, as described above.
173 if (queries.size() != 1)
166 return true; 174 return true;
175
176 OwnPtr<MediaQuery> newQuery = queries[0].release();
177 ASSERT(newQuery);
178
179 // If comparing with any of the media queries in the collection of media
180 // queries returns true terminate these steps.
181 for (size_t i = 0; i < m_queries.size(); ++i) {
182 MediaQuery* query = m_queries[i].get();
183 if (*query == *newQuery)
184 return true;
167 } 185 }
168 return false; 186
187 m_queries.append(newQuery.release());
188 return true;
169 } 189 }
170 190
171 bool MediaQuerySet::remove(const String& queryStringToRemove) 191 bool MediaQuerySet::remove(const String& queryStringToRemove)
172 { 192 {
173 OwnPtr<MediaQuery> parsedQuery = parseMediaQuery(queryStringToRemove); 193 // To "parse a media query" for a given string means to follow "the parse
174 if (!parsedQuery) 194 // a media query list" steps and return "null" if more than one media query
175 return false; 195 // is returned, or else the returned media query.
196 Vector<OwnPtr<MediaQuery> > queries;
197 parseMediaQueryList(queryStringToRemove, MediaQueryStrictMode, queries);
176 198
199 // Only continue if exactly one media query is found, as described above.
200 if (queries.size() != 1)
201 return true;
202
203 OwnPtr<MediaQuery> newQuery = queries[0].release();
204 ASSERT(newQuery);
205
206 // Remove any media query from the collection of media queries for which
207 // comparing with the media query returns true.
208 bool found = false;
177 for (size_t i = 0; i < m_queries.size(); ++i) { 209 for (size_t i = 0; i < m_queries.size(); ++i) {
178 MediaQuery* query = m_queries[i].get(); 210 MediaQuery* query = m_queries[i].get();
179 if (*query == *parsedQuery) { 211 if (*query == *newQuery) {
180 m_queries.remove(i); 212 m_queries.remove(i);
181 return true; 213 --i;
214 found = true;
182 } 215 }
183 } 216 }
184 return false; 217
218 return found;
185 } 219 }
186 220
187 void MediaQuerySet::addMediaQuery(PassOwnPtr<MediaQuery> mediaQuery) 221 void MediaQuerySet::addMediaQuery(PassOwnPtr<MediaQuery> mediaQuery)
188 { 222 {
189 m_queries.append(mediaQuery); 223 m_queries.append(mediaQuery);
190 } 224 }
191 225
192 String MediaQuerySet::mediaText() const 226 String MediaQuerySet::mediaText() const
193 { 227 {
194 StringBuilder text; 228 StringBuilder text;
(...skipping 26 matching lines...) Expand all
221 : m_mediaQueries(mediaQueries) 255 : m_mediaQueries(mediaQueries)
222 , m_parentStyleSheet(0) 256 , m_parentStyleSheet(0)
223 , m_parentRule(parentRule) 257 , m_parentRule(parentRule)
224 { 258 {
225 } 259 }
226 260
227 MediaList::~MediaList() 261 MediaList::~MediaList()
228 { 262 {
229 } 263 }
230 264
231 void MediaList::setMediaText(const String& value, ExceptionCode& ec) 265 void MediaList::setMediaText(const String& value)
232 { 266 {
233 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); 267 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule);
234 268
235 bool success = m_mediaQueries->parse(value); 269 m_mediaQueries->set(value);
236 if (!success) { 270
237 ec = SYNTAX_ERR;
238 return;
239 }
240 if (m_parentStyleSheet) 271 if (m_parentStyleSheet)
241 m_parentStyleSheet->didMutate(); 272 m_parentStyleSheet->didMutate();
242 } 273 }
243 274
244 String MediaList::item(unsigned index) const 275 String MediaList::item(unsigned index) const
245 { 276 {
246 const Vector<OwnPtr<MediaQuery> >& queries = m_mediaQueries->queryVector(); 277 const Vector<OwnPtr<MediaQuery> >& queries = m_mediaQueries->queryVector();
247 if (index < queries.size()) 278 if (index < queries.size())
248 return queries[index]->cssText(); 279 return queries[index]->cssText();
249 return String(); 280 return String();
(...skipping 11 matching lines...) Expand all
261 if (m_parentStyleSheet) 292 if (m_parentStyleSheet)
262 m_parentStyleSheet->didMutate(); 293 m_parentStyleSheet->didMutate();
263 } 294 }
264 295
265 void MediaList::appendMedium(const String& medium, ExceptionCode& ec) 296 void MediaList::appendMedium(const String& medium, ExceptionCode& ec)
266 { 297 {
267 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); 298 CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule);
268 299
269 bool success = m_mediaQueries->add(medium); 300 bool success = m_mediaQueries->add(medium);
270 if (!success) { 301 if (!success) {
271 // FIXME: Should this really be INVALID_CHARACTER_ERR?
272 ec = INVALID_CHARACTER_ERR; 302 ec = INVALID_CHARACTER_ERR;
273 return; 303 return;
274 } 304 }
305
275 if (m_parentStyleSheet) 306 if (m_parentStyleSheet)
276 m_parentStyleSheet->didMutate(); 307 m_parentStyleSheet->didMutate();
277 } 308 }
278 309
279 void MediaList::reattach(MediaQuerySet* mediaQueries) 310 void MediaList::reattach(MediaQuerySet* mediaQueries)
280 { 311 {
281 ASSERT(mediaQueries); 312 ASSERT(mediaQueries);
282 m_mediaQueries = mediaQueries; 313 m_mediaQueries = mediaQueries;
283 } 314 }
284 315
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssV alue); 377 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssV alue);
347 if (primitiveValue->isDotsPerInch() || primitiveValue->isDot sPerCentimeter()) 378 if (primitiveValue->isDotsPerInch() || primitiveValue->isDot sPerCentimeter())
348 addResolutionWarningMessageToConsole(document, mediaQuer ySet->mediaText(), primitiveValue); 379 addResolutionWarningMessageToConsole(document, mediaQuer ySet->mediaText(), primitiveValue);
349 } 380 }
350 } 381 }
351 } 382 }
352 } 383 }
353 } 384 }
354 385
355 } 386 }
OLDNEW
« no previous file with comments | « Source/core/css/MediaList.h ('k') | Source/core/css/MediaList.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698