2
* Copyright 2011 Google Inc.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
// Author: nforman@google.com (Naomi Forman)
19
// Functionality for parsing css declarations.
20
// Currently this file deals with dimensions only, but could
21
// be explanded to include other types of values.
23
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_CSS_UTIL_H_
24
#define NET_INSTAWEB_REWRITER_PUBLIC_CSS_UTIL_H_
28
#include "net/instaweb/util/public/basictypes.h"
29
#include "net/instaweb/util/public/scoped_ptr.h"
30
#include "net/instaweb/util/public/string.h"
31
#include "net/instaweb/util/public/string_util.h"
40
namespace net_instaweb {
44
// TODO(nforman): remove this namespace and put everything into the
45
// StyleExtractor class.
48
static const char kAllMedia[] = "all";
49
static const int kNoValue = -1;
52
kNoDimensions, // No dimensions found.
53
kHasHeightOnly, // Found height only.
54
kHasWidthOnly, // Found width only.
55
kHasBothDimensions, // Found both width and height.
56
kNotParsable // Found a dimension, but couldn't extract a value.
59
// Extract the width and height values out of a list of declarations.
60
// If a value was not found, it will be populated with kNoValue.
61
// This is "safe" because even if someone specifies a width:-1; it will be
63
// "If a negative length value is set on a property that does not allow
64
// negative length values, the declaration is ignored."
65
// http://www.w3.org/TR/CSS2/syndata.html#value-def-length
66
DimensionState GetDimensions(Css::Declarations* decls, int* width, int* height);
68
class StyleExtractor {
70
explicit StyleExtractor(HtmlElement* element);
71
virtual ~StyleExtractor();
74
DimensionState state() const { return state_; }
76
// If a value was not found, it will be populated with kNoValue.
77
int width() const { return width_px_; }
78
int height() const { return height_px_; }
80
// Returns true if there is any dimension specified in a style attribute,
81
// whether or not they're parsable.
82
bool HasAnyDimensions() { return (state_ != kNoDimensions); }
84
DimensionState dimension_state() { return state_; }
87
static Css::Declarations* GetDeclsFromElement(HtmlElement* element);
88
scoped_ptr<Css::Declarations> decls_;
91
DimensionState state_;
92
DISALLOW_COPY_AND_ASSIGN(StyleExtractor);
95
// Utility functions for handling CSS media types as vectors of strings.
96
// There is an argument to use StringPiece's rather than GoogleString's here,
97
// but CssFilter::FlattenImportsContext cannot use StringPiece's because it
98
// doesn't keep the original strings, so copies in GoogleString's are required.
100
// Convert a media string, from either a media attribute or after @import, to
101
// a vector of media types. If any of the input media types are 'all' then an
102
// empty vector is returned: 'all' means all media types are accepted so it
103
// subsumes all other types, and an empty vector representation is most useful.
104
void VectorizeMediaAttribute(const StringPiece& input_media,
105
StringVector* output_vector);
107
// Convert a vector of media types to a media string. If the input vector is
108
// empty then the answer is 'all', the inverse of the vectorizing function
109
// above; if you want the empty string then test the vector yourself. Otherwise
110
// the answer is a comma-separated list of media types.
111
GoogleString StringifyMediaVector(const StringVector& import_media);
113
// Checks if query is not simply a media type. In other words, whether it has
114
// a qualifier ("not" or "only") or media expressions (like "and (color)").
115
bool IsComplexMediaQuery(const Css::MediaQuery& query);
117
// Convert a set of MediaQueries to a vector of UTF-8 GoogleString's for use
118
// of the above functions. Elements are trimmed and any empty elements are
121
// Only simple media queries are accepted, returns false for complex queries.
122
bool ConvertMediaQueriesToStringVector(const Css::MediaQueries& in_vector,
123
StringVector* out_vector);
125
// Convert a vector of UTF-8 GoogleString's to MediaQueries. Elements are
126
// trimmed and any empty elements are ignored. The strings are interpreted
127
// as simple media types (no complex media query syntax like "not screen" or
128
// "(max-width: 200px)").
129
void ConvertStringVectorToMediaQueries(const StringVector& in_vector,
130
Css::MediaQueries* out_vector);
132
// Clear the given vector if it contains the media 'all'. This is required
133
// because Css::Parser doesn't treat 'all' specially but we do for efficiency.
134
void ClearVectorIfContainsMediaAll(StringVector* media);
136
// Can this media attribute include some kind of screen?
137
bool CanMediaAffectScreen(const StringPiece& media);
139
// Strip a parsed selector down to a string that can be used by a
140
// querySelectorAll call in the browser to select DOM elements.
141
GoogleString JsDetectableSelector(const Css::Selector& selector);
143
// Eliminate all elements from the first vector that are not in the second
144
// vector, with the caveat that an empty vector (first or second) means 'the
145
// set of all possible values', meaning that if the second vector is empty
146
// then no elements are removed from the first vector, and if the first vector
147
// is empty then the second vector is copied into it. Both vectors must be
150
void EliminateElementsNotIn(std::vector<T>* sorted_inner,
151
const std::vector<T>& sorted_outer) {
152
if (!sorted_outer.empty()) {
153
if (sorted_inner->empty()) {
154
*sorted_inner = sorted_outer;
156
typename std::vector<T>::const_iterator outer_iter = sorted_outer.begin();
157
typename std::vector<T>::iterator inner_iter = sorted_inner->begin();
159
while (inner_iter != sorted_inner->end()) {
160
if (outer_iter == sorted_outer.end()) {
161
// No more outer elements => delete all remaining inner elements.
162
inner_iter = sorted_inner->erase(inner_iter, sorted_inner->end());
163
} else if (*outer_iter == *inner_iter) {
164
// This inner element is in the outer => keep it and move on.
167
} else if (*outer_iter < *inner_iter) {
168
// This outer element isn't in the inner => skip it, try the next.
171
// This inner element isn't in the outer => delete it, move on.
172
inner_iter = sorted_inner->erase(inner_iter);
179
} // namespace css_util
181
} // namespace net_instaweb
183
#endif // NET_INSTAWEB_REWRITER_PUBLIC_CSS_UTIL_H_