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

Side by Side Diff: sky/engine/core/html/HTMLMetaElement-in.cpp

Issue 654693004: Remove meta viewport and @viewport CSS rules. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2010 Apple Inc. All rights reserved. 5 * Copyright (C) 2003, 2010 Apple Inc. All rights reserved.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public 8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
(...skipping 16 matching lines...) Expand all
27 #include "core/dom/Document.h" 27 #include "core/dom/Document.h"
28 #include "core/dom/ElementTraversal.h" 28 #include "core/dom/ElementTraversal.h"
29 #include "core/frame/LocalFrame.h" 29 #include "core/frame/LocalFrame.h"
30 #include "core/frame/Settings.h" 30 #include "core/frame/Settings.h"
31 #include "core/inspector/ConsoleMessage.h" 31 #include "core/inspector/ConsoleMessage.h"
32 #include "core/loader/FrameLoaderClient.h" 32 #include "core/loader/FrameLoaderClient.h"
33 #include "platform/RuntimeEnabledFeatures.h" 33 #include "platform/RuntimeEnabledFeatures.h"
34 34
35 namespace blink { 35 namespace blink {
36 36
37 #define DEFINE_ARRAY_FOR_MATCHING(name, source, maxMatchLength) \
38 const UChar* name; \
39 const unsigned uMaxMatchLength = maxMatchLength; \
40 UChar characterBuffer[uMaxMatchLength]; \
41 if (!source.is8Bit()) { \
42 name = source.characters16(); \
43 } else { \
44 unsigned bufferLength = std::min(uMaxMatchLength, source.length()); \
45 const LChar* characters8 = source.characters8(); \
46 for (unsigned i = 0; i < bufferLength; ++i) \
47 characterBuffer[i] = characters8[i]; \
48 name = characterBuffer; \
49 }
50
51 inline HTMLMetaElement::HTMLMetaElement(Document& document) 37 inline HTMLMetaElement::HTMLMetaElement(Document& document)
52 : HTMLElement(HTMLNames::metaTag, document) 38 : HTMLElement(HTMLNames::metaTag, document)
53 { 39 {
54 ScriptWrappable::init(this); 40 ScriptWrappable::init(this);
55 } 41 }
56 42
57 DEFINE_NODE_FACTORY(HTMLMetaElement) 43 DEFINE_NODE_FACTORY(HTMLMetaElement)
58 44
59 static bool isInvalidSeparator(UChar c)
60 {
61 return c == ';';
62 }
63
64 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
65 static bool isSeparator(UChar c)
66 {
67 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ' ,' || c == '\0';
68 }
69
70 void HTMLMetaElement::parseContentAttribute(const String& content, KeyValuePairC allback callback, void* data)
71 {
72 bool error = false;
73
74 // Tread lightly in this code -- it was specifically designed to mimic Win I E's parsing behavior.
75 unsigned keyBegin, keyEnd;
76 unsigned valueBegin, valueEnd;
77
78 String buffer = content.lower();
79 unsigned length = buffer.length();
80 for (unsigned i = 0; i < length; /* no increment here */) {
81 // skip to first non-separator, but don't skip past the end of the strin g
82 while (isSeparator(buffer[i])) {
83 if (i >= length)
84 break;
85 i++;
86 }
87 keyBegin = i;
88
89 // skip to first separator
90 while (!isSeparator(buffer[i])) {
91 error |= isInvalidSeparator(buffer[i]);
92 if (i >= length)
93 break;
94 i++;
95 }
96 keyEnd = i;
97
98 // skip to first '=', but don't skip past a ',' or the end of the string
99 while (buffer[i] != '=') {
100 error |= isInvalidSeparator(buffer[i]);
101 if (buffer[i] == ',' || i >= length)
102 break;
103 i++;
104 }
105
106 // skip to first non-separator, but don't skip past a ',' or the end of the string
107 while (isSeparator(buffer[i])) {
108 if (buffer[i] == ',' || i >= length)
109 break;
110 i++;
111 }
112 valueBegin = i;
113
114 // skip to first separator
115 while (!isSeparator(buffer[i])) {
116 error |= isInvalidSeparator(buffer[i]);
117 if (i >= length)
118 break;
119 i++;
120 }
121 valueEnd = i;
122
123 ASSERT_WITH_SECURITY_IMPLICATION(i <= length);
124
125 String keyString = buffer.substring(keyBegin, keyEnd - keyBegin);
126 String valueString = buffer.substring(valueBegin, valueEnd - valueBegin) ;
127 (this->*callback)(keyString, valueString, data);
128 }
129 if (error) {
130 String message = "Error parsing a meta element's content: ';' is not a v alid key-value pair separator. Please use ',' instead.";
131 document().addConsoleMessage(ConsoleMessage::create(RenderingMessageSour ce, WarningMessageLevel, message));
132 }
133 }
134
135 static inline float clampLengthValue(float value)
136 {
137 // Limits as defined in the css-device-adapt spec.
138 if (value != ViewportDescription::ValueAuto)
139 return std::min(float(10000), std::max(value, float(1)));
140 return value;
141 }
142
143 static inline float clampScaleValue(float value)
144 {
145 // Limits as defined in the css-device-adapt spec.
146 if (value != ViewportDescription::ValueAuto)
147 return std::min(float(10), std::max(value, float(0.1)));
148 return value;
149 }
150
151 float HTMLMetaElement::parsePositiveNumber(const String& keyString, const String & valueString, bool* ok)
152 {
153 size_t parsedLength;
154 float value;
155 if (valueString.is8Bit())
156 value = charactersToFloat(valueString.characters8(), valueString.length( ), parsedLength);
157 else
158 value = charactersToFloat(valueString.characters16(), valueString.length (), parsedLength);
159 if (!parsedLength) {
160 reportViewportWarning(UnrecognizedViewportArgumentValueError, valueStrin g, keyString);
161 if (ok)
162 *ok = false;
163 return 0;
164 }
165 if (parsedLength < valueString.length())
166 reportViewportWarning(TruncatedViewportArgumentValueError, valueString, keyString);
167 if (ok)
168 *ok = true;
169 return value;
170 }
171
172 Length HTMLMetaElement::parseViewportValueAsLength(const String& keyString, cons t String& valueString)
173 {
174 // 1) Non-negative number values are translated to px lengths.
175 // 2) Negative number values are translated to auto.
176 // 3) device-width and device-height are used as keywords.
177 // 4) Other keywords and unknown values translate to 0.0.
178
179 unsigned length = valueString.length();
180 DEFINE_ARRAY_FOR_MATCHING(characters, valueString, 13);
181 SWITCH(characters, length) {
182 CASE("device-width") {
183 return Length(DeviceWidth);
184 }
185 CASE("device-height") {
186 return Length(DeviceHeight);
187 }
188 }
189
190 float value = parsePositiveNumber(keyString, valueString);
191
192 if (value < 0)
193 return Length(); // auto
194
195 return Length(clampLengthValue(value), Fixed);
196 }
197
198 float HTMLMetaElement::parseViewportValueAsZoom(const String& keyString, const S tring& valueString, bool& computedValueMatchesParsedValue)
199 {
200 // 1) Non-negative number values are translated to <number> values.
201 // 2) Negative number values are translated to auto.
202 // 3) yes is translated to 1.0.
203 // 4) device-width and device-height are translated to 10.0.
204 // 5) no and unknown values are translated to 0.0
205
206 computedValueMatchesParsedValue = false;
207 unsigned length = valueString.length();
208 DEFINE_ARRAY_FOR_MATCHING(characters, valueString, 13);
209 SWITCH(characters, length) {
210 CASE("yes") {
211 return 1;
212 }
213 CASE("no") {
214 return 0;
215 }
216 CASE("device-width") {
217 return 10;
218 }
219 CASE("device-height") {
220 return 10;
221 }
222 }
223
224 float value = parsePositiveNumber(keyString, valueString);
225
226 if (value < 0)
227 return ViewportDescription::ValueAuto;
228
229 if (value > 10.0)
230 reportViewportWarning(MaximumScaleTooLargeError, String(), String());
231
232 float clampedValue = clampScaleValue(value);
233 if (clampedValue == value)
234 computedValueMatchesParsedValue = true;
235
236 return clampedValue;
237 }
238
239 bool HTMLMetaElement::parseViewportValueAsUserZoom(const String& keyString, cons t String& valueString, bool& computedValueMatchesParsedValue)
240 {
241 // yes and no are used as keywords.
242 // Numbers >= 1, numbers <= -1, device-width and device-height are mapped to yes.
243 // Numbers in the range <-1, 1>, and unknown values, are mapped to no.
244
245 computedValueMatchesParsedValue = false;
246 unsigned length = valueString.length();
247 DEFINE_ARRAY_FOR_MATCHING(characters, valueString, 13);
248 SWITCH(characters, length) {
249 CASE("yes") {
250 computedValueMatchesParsedValue = true;
251 return true;
252 }
253 CASE("no") {
254 computedValueMatchesParsedValue = true;
255 return false;
256 }
257 CASE("device-width") {
258 return true;
259 }
260 CASE("device-height") {
261 return true;
262 }
263 }
264
265 float value = parsePositiveNumber(keyString, valueString);
266 if (fabs(value) < 1)
267 return false;
268
269 return true;
270 }
271
272 float HTMLMetaElement::parseViewportValueAsDPI(const String& keyString, const St ring& valueString)
273 {
274 unsigned length = valueString.length();
275 DEFINE_ARRAY_FOR_MATCHING(characters, valueString, 10);
276 SWITCH(characters, length) {
277 CASE("device-dpi") {
278 return ViewportDescription::ValueDeviceDPI;
279 }
280 CASE("low-dpi") {
281 return ViewportDescription::ValueLowDPI;
282 }
283 CASE("medium-dpi") {
284 return ViewportDescription::ValueMediumDPI;
285 }
286 CASE("high-dpi") {
287 return ViewportDescription::ValueHighDPI;
288 }
289 }
290
291 bool ok;
292 float value = parsePositiveNumber(keyString, valueString, &ok);
293 if (!ok || value < 70 || value > 400)
294 return ViewportDescription::ValueAuto;
295
296 return value;
297 }
298
299 void HTMLMetaElement::processViewportKeyValuePair(const String& keyString, const String& valueString, void* data)
300 {
301 ViewportDescription* description = static_cast<ViewportDescription*>(data);
302
303 unsigned length = keyString.length();
304
305 DEFINE_ARRAY_FOR_MATCHING(characters, keyString, 17);
306 SWITCH(characters, length) {
307 CASE("width") {
308 const Length& width = parseViewportValueAsLength(keyString, valueStr ing);
309 if (width.isAuto())
310 return;
311 description->minWidth = Length(ExtendToZoom);
312 description->maxWidth = width;
313 return;
314 }
315 CASE("height") {
316 const Length& height = parseViewportValueAsLength(keyString, valueSt ring);
317 if (height.isAuto())
318 return;
319 description->minHeight = Length(ExtendToZoom);
320 description->maxHeight = height;
321 return;
322 }
323 CASE("initial-scale") {
324 description->zoom = parseViewportValueAsZoom(keyString, valueString, description->zoomIsExplicit);
325 return;
326 }
327 CASE("minimum-scale") {
328 description->minZoom = parseViewportValueAsZoom(keyString, valueStri ng, description->minZoomIsExplicit);
329 return;
330 }
331 CASE("maximum-scale") {
332 description->maxZoom = parseViewportValueAsZoom(keyString, valueStri ng, description->maxZoomIsExplicit);
333 return;
334 }
335 CASE("user-scalable") {
336 description->userZoom = parseViewportValueAsUserZoom(keyString, valu eString, description->userZoomIsExplicit);
337 return;
338 }
339 CASE("target-densitydpi") {
340 description->deprecatedTargetDensityDPI = parseViewportValueAsDPI(ke yString, valueString);
341 reportViewportWarning(TargetDensityDpiUnsupported, String(), String( ));
342 return;
343 }
344 CASE("minimal-ui") {
345 // Ignore vendor-specific argument.
346 return;
347 }
348 }
349 reportViewportWarning(UnrecognizedViewportArgumentKeyError, keyString, Strin g());
350 }
351
352 static const char* viewportErrorMessageTemplate(ViewportErrorCode errorCode)
353 {
354 static const char* const errors[] = {
355 "The key \"%replacement1\" is not recognized and ignored.",
356 "The value \"%replacement1\" for key \"%replacement2\" is invalid, and h as been ignored.",
357 "The value \"%replacement1\" for key \"%replacement2\" was truncated to its numeric prefix.",
358 "The value for key \"maximum-scale\" is out of bounds and the value has been clamped.",
359 "The key \"target-densitydpi\" is not supported.",
360 };
361
362 return errors[errorCode];
363 }
364
365 static MessageLevel viewportErrorMessageLevel(ViewportErrorCode errorCode)
366 {
367 switch (errorCode) {
368 case TruncatedViewportArgumentValueError:
369 case TargetDensityDpiUnsupported:
370 case UnrecognizedViewportArgumentKeyError:
371 case UnrecognizedViewportArgumentValueError:
372 case MaximumScaleTooLargeError:
373 return WarningMessageLevel;
374 }
375
376 ASSERT_NOT_REACHED();
377 return ErrorMessageLevel;
378 }
379
380 void HTMLMetaElement::reportViewportWarning(ViewportErrorCode errorCode, const S tring& replacement1, const String& replacement2)
381 {
382 if (!document().frame())
383 return;
384
385 String message = viewportErrorMessageTemplate(errorCode);
386 if (!replacement1.isNull())
387 message.replace("%replacement1", replacement1);
388 if (!replacement2.isNull())
389 message.replace("%replacement2", replacement2);
390
391 // FIXME: This message should be moved off the console once a solution to ht tps://bugs.webkit.org/show_bug.cgi?id=103274 exists.
392 document().addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, viewportErrorMessageLevel(errorCode), message));
393 }
394
395 void HTMLMetaElement::processViewportContentAttribute(const String& content, Vie wportDescription::Type origin)
396 {
397 ASSERT(!content.isNull());
398
399 if (!document().shouldOverrideLegacyDescription(origin))
400 return;
401
402 ViewportDescription descriptionFromLegacyTag(origin);
403
404 parseContentAttribute(content, &HTMLMetaElement::processViewportKeyValuePair , (void*)&descriptionFromLegacyTag);
405
406 if (descriptionFromLegacyTag.minZoom == ViewportDescription::ValueAuto)
407 descriptionFromLegacyTag.minZoom = 0.25;
408
409 if (descriptionFromLegacyTag.maxZoom == ViewportDescription::ValueAuto) {
410 descriptionFromLegacyTag.maxZoom = 5;
411 descriptionFromLegacyTag.minZoom = std::min(descriptionFromLegacyTag.min Zoom, float(5));
412 }
413
414 document().setViewportDescription(descriptionFromLegacyTag);
415 }
416
417
418 void HTMLMetaElement::parseAttribute(const QualifiedName& name, const AtomicStri ng& value) 45 void HTMLMetaElement::parseAttribute(const QualifiedName& name, const AtomicStri ng& value)
419 { 46 {
420 if (name == HTMLNames::http_equivAttr || name == HTMLNames::contentAttr) { 47 if (name == HTMLNames::http_equivAttr || name == HTMLNames::contentAttr) {
421 process(); 48 process();
422 return; 49 return;
423 } 50 }
424 51
425 if (name != HTMLNames::nameAttr) 52 if (name != HTMLNames::nameAttr)
426 HTMLElement::parseAttribute(name, value); 53 HTMLElement::parseAttribute(name, value);
427 } 54 }
(...skipping 13 matching lines...) Expand all
441 { 68 {
442 if (!inDocument()) 69 if (!inDocument())
443 return; 70 return;
444 71
445 // All below situations require a content attribute (which can be the empty string). 72 // All below situations require a content attribute (which can be the empty string).
446 const AtomicString& contentValue = getAttribute(HTMLNames::contentAttr); 73 const AtomicString& contentValue = getAttribute(HTMLNames::contentAttr);
447 if (contentValue.isNull()) 74 if (contentValue.isNull())
448 return; 75 return;
449 76
450 const AtomicString& nameValue = getAttribute(HTMLNames::nameAttr); 77 const AtomicString& nameValue = getAttribute(HTMLNames::nameAttr);
451 if (!nameValue.isEmpty()) { 78 if (!nameValue.isEmpty() && equalIgnoringCase(nameValue, "referrer"))
452 if (equalIgnoringCase(nameValue, "viewport")) 79 document().processReferrerPolicy(contentValue);
453 processViewportContentAttribute(contentValue, ViewportDescription::V iewportMeta);
454 else if (equalIgnoringCase(nameValue, "referrer"))
455 document().processReferrerPolicy(contentValue);
456 else if (equalIgnoringCase(nameValue, "handheldfriendly") && equalIgnori ngCase(contentValue, "true"))
457 processViewportContentAttribute("width=device-width", ViewportDescri ption::HandheldFriendlyMeta);
458 else if (equalIgnoringCase(nameValue, "mobileoptimized"))
459 processViewportContentAttribute("width=device-width, initial-scale=1 ", ViewportDescription::MobileOptimizedMeta);
460 }
461 80
462 // Get the document to process the tag, but only if we're actually part of D OM 81 // Get the document to process the tag, but only if we're actually part of D OM
463 // tree (changing a meta tag while it's not in the tree shouldn't have any e ffect 82 // tree (changing a meta tag while it's not in the tree shouldn't have any e ffect
464 // on the document). 83 // on the document).
465 84
466 const AtomicString& httpEquivValue = getAttribute(HTMLNames::http_equivAttr) ; 85 const AtomicString& httpEquivValue = getAttribute(HTMLNames::http_equivAttr) ;
467 if (!httpEquivValue.isEmpty()) 86 if (!httpEquivValue.isEmpty())
468 document().processHttpEquiv(httpEquivValue, contentValue, false); 87 document().processHttpEquiv(httpEquivValue, contentValue, false);
469 } 88 }
470 89
471 const AtomicString& HTMLMetaElement::content() const 90 const AtomicString& HTMLMetaElement::content() const
472 { 91 {
473 return getAttribute(HTMLNames::contentAttr); 92 return getAttribute(HTMLNames::contentAttr);
474 } 93 }
475 94
476 const AtomicString& HTMLMetaElement::httpEquiv() const 95 const AtomicString& HTMLMetaElement::httpEquiv() const
477 { 96 {
478 return getAttribute(HTMLNames::http_equivAttr); 97 return getAttribute(HTMLNames::http_equivAttr);
479 } 98 }
480 99
481 const AtomicString& HTMLMetaElement::name() const 100 const AtomicString& HTMLMetaElement::name() const
482 { 101 {
483 return getAttribute(HTMLNames::nameAttr); 102 return getAttribute(HTMLNames::nameAttr);
484 } 103 }
485 104
486 } 105 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698