blob: 31f425b22af9664433920511b08ce59f231cbb29 [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: chenyu@google.com (Yu Chen), morlovich@google.com (Maks Orlovich)
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_MAKE_SHOW_ADS_ASYNC_FILTER_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_MAKE_SHOW_ADS_ASYNC_FILTER_H_
#include "net/instaweb/rewriter/public/common_filter.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/html/html_element.h"
#include "pagespeed/kernel/html/html_filter.h"
#include "pagespeed/kernel/html/html_node.h"
#include "pagespeed/opt/ads/show_ads_snippet_parser.h"
namespace net_instaweb {
class Statistics;
class Variable;
// This filter converts from synchronous AdSense snippets (showads.js)
// to async ones (adsbygoogle.js)
class MakeShowAdsAsyncFilter : public CommonFilter {
public:
static const char kShowAdsSnippetsConverted[];
static const char kShowAdsSnippetsNotConverted[];
static const char kShowAdsApiReplacedForAsync[];
explicit MakeShowAdsAsyncFilter(RewriteDriver* rewrite_driver);
virtual ~MakeShowAdsAsyncFilter();
static void InitStats(Statistics* statistics);
// Overrides CommonFilter
virtual void StartDocumentImpl();
virtual void StartElementImpl(HtmlElement* element);
virtual void EndElementImpl(HtmlElement* element);
// Overrides HtmlFilter
virtual const char* Name() const {
return "MakeShowAdsAsyncFilter";
}
virtual void Characters(HtmlCharactersNode* characters);
ScriptUsage GetScriptUsage() const override { return kWillInjectScripts; }
private:
// Parses an element that has 'content'; the parsed attributes are stored
// in 'parsed_attributes'. It returns true if the element is a showads element
// that can be changed to be async. 'parsed_attributes' are
// meaningful only when this method returns true.
//
// Note that this is in particular looking for the inline snippets that
// set various google_ad_ variables, rather than <script src="showads">
bool IsApplicableShowAds(
const GoogleString& content,
ShowAdsSnippetParser::AttributeMap* parsed_attributes) const;
// Creates elements for an adsbygoogle snippet that is equivalent to element
// 'show_ads_element', whose attributes are parsed in 'parsed_attributes', and
// replace the 'show_ads_element' with the created elements.
void ReplaceShowAdsWithAdsByGoogleElement(
const ShowAdsSnippetParser::AttributeMap& parsed_attributes,
HtmlElement* show_ads_elment);
void ReplaceShowAdsApiCallWithAdsByGoogleApiCall(
HtmlElement* show_ads_elment);
// The current element if it is a script element, NULL otherwise.
HtmlElement* current_script_element_;
// Contents of 'current_script_element_'.
GoogleString current_script_element_contents_;
// These two variables ('has_ads_by_google_js_' and
// 'num_pending_show_ads_push_replacements_') are used when replacing a
// showads ad by an adsbygoogle ad. More details are given below.
//
// In order to display adsbygoogle ads in an HTML page, the required JS
// (adsbygoogle.js) must be loaded at least once a page, that is, a <script>
// with src pointing to adsbygoogle.js should be present in the page.
// For each ad, there must be
// - a valid adsbygoogle <ins> element and
// - a <script> element with a snippet that calls adsbygoogle API.
// The <script> element that calls adsbygoogle API must be after the <ins>
// element; it does not need to be immediately after the <ins> element.
//
// In order to display a showads ad in an HTML page, there must be
// - a valid showads data <script> element and
// - a <script> element with a snippet that calls showads API.
// The <script> element that calls showads API must be after the showads data
// <script> element; it does not need to be immediately after the showads data
// <script> element.
//
// In this class, we use 'has_ads_by_google_js_' to track whether a
// <script> element with src pointing to adsbygoogle.js has been seen.
//
// Each time an applicable showads data <script> element is seen, it is
// replaced with an adsbygoogle <ins> element. And if no <script> element with
// src pointing to adsbygoogle.js has been seen, we will create one and
// insert it to the page, and also set 'has_ads_by_google_js_' to true to
// prevent us from the doing this more than once.
bool has_ads_by_google_js_;
// The number of <script> elements with a snippet that calls showads API and
// - that are expected to be paired with a replaced showads data <script>
// element, and
// - that has not been replaced by a <script> element with a snippet that
// calls adsbygoogle API.
int32 num_pending_show_ads_api_call_replacements_;
ShowAdsSnippetParser show_ads_snippet_parser_;
// Statistics variables.
Variable* show_ads_snippets_converted_count_;
Variable* show_ads_snippets_not_converted_count_;
Variable* show_ads_api_replaced_for_async_;
DISALLOW_COPY_AND_ASSIGN(MakeShowAdsAsyncFilter);
};
} // namespace net_instaweb
#endif // NET_INSTAWEB_REWRITER_PUBLIC_MAKE_SHOW_ADS_ASYNC_FILTER_H_