2
* Copyright 2013 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: morlovich@google.com (Maksim Orlovich)
19
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_CSS_SUMMARIZER_BASE_H_
20
#define NET_INSTAWEB_REWRITER_PUBLIC_CSS_SUMMARIZER_BASE_H_
24
#include "net/instaweb/htmlparse/public/html_element.h"
25
#include "net/instaweb/rewriter/public/resource_slot.h"
26
#include "net/instaweb/rewriter/public/rewrite_filter.h"
27
#include "net/instaweb/util/public/basictypes.h"
28
#include "net/instaweb/util/public/scoped_ptr.h"
29
#include "net/instaweb/util/public/string.h"
30
#include "net/instaweb/util/public/string_util.h"
38
namespace net_instaweb {
41
class HtmlCharactersNode;
47
// This class helps implement filters that try to compute some properties of all
48
// the screen-affecting CSS in the page except for scoped <style> blocks (which
49
// are left untouched). They are expected to override Summarize() to perform the
50
// per-CSS computation; then at SummariesDone() they can lookup summaries via
51
// NumStyles/GetSummaryForStyle.
52
class CssSummarizerBase : public RewriteFilter {
54
static const char kNumCssUsedForCriticalCssComputation[];
55
static const char kNumCssNotUsedForCriticalCssComputation[];
57
explicit CssSummarizerBase(RewriteDriver* driver);
58
virtual ~CssSummarizerBase();
60
static void InitStats(Statistics* statistics);
67
// Computation/Fetches ongoing, we don't have a result yet.
70
// CSS parse error we can't recover from.
71
kSummaryCssParseError,
73
// Could not create the resource object, so its URL is malformed or we do
74
// not have permission to rewrite it.
75
kSummaryResourceCreationFailed,
77
// Fetch result unusable, either error or not cacheable.
78
kSummaryInputUnavailable,
80
// Slot got removed by an another optimization.
86
: state(kSummaryStillPending),
88
is_inside_noscript(false) {}
90
// data actually computed by the subclass's Summarize method. Make sure to
91
// check state == kSummaryOk before using it.
94
// State of computation of 'data'.
97
// Human-readable description of the location of the CSS. For use in debug
99
GoogleString location;
101
// Base to use for resolving links in the CSS resource.
104
// CSS media there were applied to the resource by the HTML.
105
GoogleString media_from_html;
107
// If it's an external stylesheet, the value of the rel attribute
110
// True if it's a <link rel=stylesheet href=>, false for <style>
113
// True if the style was included inside a noscript section.
114
bool is_inside_noscript;
117
// This method should be overridden in case the subclass's summary computation
118
// depends on things other than the input CSS.
119
virtual GoogleString CacheKeySuffix() const;
121
// This method should be overridden if some CSS should not go through the
122
// summarization process (eg because it uses an inapplicable media type and
123
// we'll just throw it away when we're done anyway). By default all CSS
124
// must be summarized.
125
virtual bool MustSummarize(HtmlElement* element) const {
129
// This should be overridden to compute a per-resource summary.
130
// The method should not modify the object state, and only
131
// put the result into *out as it may not be invoked in case of a
132
// cache hit. The subclass may mutate *stylesheet if it so wishes.
134
// Note: this is called on a rewrite thread, so it should not access
135
// HTML parser state.
136
virtual void Summarize(Css::Stylesheet* stylesheet,
137
GoogleString* out) const = 0;
139
// This can be optionally overridden to modify a CSS element based on a
140
// successfully computed summary. It might not be invoked if cached
141
// information is not readily available, and will not be invoked if CSS
142
// parsing failed or some other error occurred. Invocation occurs from a
143
// thread with HTML parser context state, so both DOM modification and
144
// GetSummaryForStyle() are safe to use. If invoked, the method will be called
145
// before SummariesDone().
147
// pos is the position of the element in the summary table.
149
// element points to the <link> or <style> element that was summarized.
150
// If the element was a <style>, char_node will also point to its contents
151
// node; otherwise it will be NULL. Overrides need to set is_element_deleted
152
// to true if they delete the element.
154
// The default implementation does nothing.
155
virtual void RenderSummary(int pos,
156
HtmlElement* element,
157
HtmlCharactersNode* char_node,
158
bool* is_element_deleted);
160
// Like RenderSummary, but called in cases where we're unable to render a
161
// summary for some reason (including not being able to compute one).
162
// Note: not called when we're canceled due to disable_further_processing.
164
// Like with RenderSummary, this corresponds to entry [pos] in the summary
165
// table, and elements points to the <link> or <style> containing CSS,
166
// with char_node being non-null in case it was a <style>. Overrides need
167
// to set is_element_deleted to true if they delete the element.
168
virtual void WillNotRenderSummary(int pos,
169
HtmlElement* element,
170
HtmlCharactersNode* char_node,
171
bool* is_element_deleted);
173
// This is called at the end of the document when all outstanding summary
174
// computations have completed, regardless of whether successful or not. It
175
// will not be called at all if they are still ongoing, however.
177
// It's called from a context which allows HTML parser state access. You can
178
// insert things at end of document by constructing an HtmlNode* using the
179
// factories in HtmlParse and calling CommonFilter::InsertNodeAtBodyEnd(node).
181
// Note that the timing of this can vary widely --- it can occur during
182
// initial parse, during the render phase, or even at RenderDone, so
183
// implementors should not make assumptions about what other filters may have
186
// Base version does nothing.
187
virtual void SummariesDone();
189
// Returns total number of <link> and <style> elements we encountered.
190
// This includes those for which we had problem computing summary information.
192
// Should be called from a thread context that has HTML parser state access.
193
int NumStyles() const { return static_cast<int>(summaries_.size()); }
195
// Returns summary computed for the pos'th style in the document.
197
// pos must be in [0, NumStyles())
199
// Should be called from a thread context that has HTML parser state access.
200
const SummaryInfo& GetSummaryForStyle(int pos) const {
201
return summaries_.at(pos);
204
// Overrides of the filter APIs. You MUST call through to this class's
205
// implementations if you override them.
206
virtual void StartDocumentImpl();
207
virtual void EndDocument();
208
virtual void StartElementImpl(HtmlElement* element);
209
virtual void Characters(HtmlCharactersNode* characters);
210
virtual void EndElementImpl(HtmlElement* element);
211
virtual void RenderDone();
213
virtual RewriteContext* MakeRewriteContext();
218
// Clean out private data.
221
// Invokes SummariesDone and, if the debug filter is on, injects a comment
222
// describing what happened with every CSS resource.
223
void ReportSummariesDone();
225
// Starts the asynchronous rewrite process for inline CSS 'text', contained
226
// within the style element 'style'.
227
void StartInlineRewrite(HtmlElement* style, HtmlCharactersNode* text);
229
// Starts the asynchronous rewrite process for external CSS referenced by
230
// attribute 'src' of 'link', whose rel attribute is 'rel'.
231
void StartExternalRewrite(HtmlElement* link, HtmlElement::Attribute* src,
234
// Creates our rewrite context for the given slot and registers it
235
// with the summaries_ vector, filling in the SummaryInfo struct in
236
// a pending state. The context will still need to have SetupInlineRewrite
237
// or SetupExternalRewrite and InitiateRewrite called on it.
238
// location is used to identify the resource in debug comments.
239
Context* CreateContextAndSummaryInfo(const HtmlElement* element,
241
const ResourceSlotPtr& slot,
242
const GoogleString& location,
243
StringPiece base_for_resources,
246
ResourceSlot* MakeSlotForInlineCss(HtmlElement* element,
247
const StringPiece& content);
249
// Stores all the computed summaries.
250
std::vector<SummaryInfo> summaries_;
252
scoped_ptr<AbstractMutex> progress_lock_;
253
int outstanding_rewrites_; // guarded by progress_lock_
254
bool saw_end_of_document_; // guarded by progress_lock_
255
// Lists indexes into summaries_ vector that got canceled due to
256
// disable_further_processing. It's written to in the Rewrite thread,
257
// and then pulled into summaries_ from an HTML thread.
258
std::vector<int> canceled_summaries_; // guarded by progress_lock_
260
HtmlElement* style_element_; // The element we are in, or NULL.
262
Variable* num_css_used_for_critical_css_computation_;
263
Variable* num_css_not_used_for_critical_css_computation_;
265
DISALLOW_COPY_AND_ASSIGN(CssSummarizerBase);
268
} // namespace net_instaweb
270
#endif // NET_INSTAWEB_REWRITER_PUBLIC_CSS_SUMMARIZER_BASE_H_