| /* |
| * 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: stevensr@google.com (Ryan Stevens) |
| |
| #ifndef NET_INSTAWEB_REWRITER_PUBLIC_MOBILIZE_REWRITE_FILTER_H_ |
| #define NET_INSTAWEB_REWRITER_PUBLIC_MOBILIZE_REWRITE_FILTER_H_ |
| |
| #include "net/instaweb/rewriter/public/common_filter.h" |
| #include "net/instaweb/rewriter/public/mobilize_decision_trees.h" |
| #include "net/instaweb/rewriter/public/rewrite_driver.h" |
| #include "net/instaweb/rewriter/public/rewrite_options.h" |
| #include "net/instaweb/rewriter/public/static_asset_manager.h" |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/statistics.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/html/html_element.h" |
| #include "pagespeed/kernel/html/html_name.h" |
| #include "pagespeed/kernel/html/html_node.h" |
| #include "pagespeed/kernel/http/user_agent_matcher.h" |
| |
| namespace net_instaweb { |
| |
| // Rewrite HTML to be mobile-friendly based on "data-mobile-role" attributes in |
| // the HTML tags. To reorganize the DOM, the filter puts containers at the end |
| // of the body into which we move tagged elements. The containers are later |
| // removed after the filter is done processing the document body. The filter |
| // applies the following transformations: |
| // - Add mobile <style> and <meta name="viewport"...> tags to the head. |
| // - Remove all table tags (but keep the content). Almost all tables in desktop |
| // HTML are for formatting, not displaying data, and they tend not to resize |
| // well for mobile. The easiest thing to do is to simply strip out the |
| // formatting and hope the content reflows properly. |
| // - Reorder body of the HTML DOM elements based on mobile role. Any elements |
| // which don't have an important parent will get removed, except for a |
| // special set of "keeper" tags (like <script> or <style>). The keeper tags |
| // are retained because they are often necessary for the website to work |
| // properly, and because they have no visible appearance on the page. |
| // - Remove all elements from inside data-mobile-role="navigational" elements |
| // except in a special set of nav tags (notably <a>). Nav sections often do |
| // not resize well due to fixed width formatting and drop-down menus, so it |
| // is often necessary to pull out what you want, instead of shuffling around |
| // what is there. |
| // |
| // Remaining todos: |
| // - TODO (stevensr): This script does not handle flush windows in the body. |
| // - TODO (stevensr): It would be nice to tweak the table-xform behavior via |
| // options. Also, there has been mention that removing tables across flush |
| // windows could be problematic. This should be addressed at some point. |
| // - TODO (stevensr): Enable this filter only for mobile UAs, and have a query |
| // param option to turn it on for all UAs for debugging. |
| // - TODO (stevensr): Write pcache entry if rewriting page fails. We should |
| // then probably inject some JS to auto-refresh the page so the user does not |
| // see the badly rewritten result. |
| // - TODO (stevensr): Add a separate wildcard option to allow/disallow URLs |
| // from using this filter. Of course sites can use our existing Allow and |
| // Disallow directives but that turns off all optimizations, and this one is |
| // one that might be extra finicky (e.g. don't touch my admin pages). |
| // - TODO (stevensr): Turn on css_move_to_head_filter.cc to reorder elements |
| // we inject into the head. |
| class MobilizeRewriteFilter : public CommonFilter { |
| public: |
| static const char kPagesMobilized[]; |
| static const char kKeeperBlocks[]; |
| static const char kHeaderBlocks[]; |
| static const char kNavigationalBlocks[]; |
| static const char kContentBlocks[]; |
| static const char kMarginalBlocks[]; |
| static const char kDeletedElements[]; |
| |
| explicit MobilizeRewriteFilter(RewriteDriver* rewrite_driver); |
| virtual ~MobilizeRewriteFilter(); |
| |
| static void InitStats(Statistics* statistics); |
| |
| // True if options or request UA suggest we will actually do mobilization. |
| static bool IsApplicableFor(RewriteDriver* driver); |
| static bool IsApplicableFor(const RewriteOptions* options, |
| const char* user_agent, |
| const UserAgentMatcher* matcher); |
| virtual void DetermineEnabled(GoogleString* disabled_reason); |
| virtual void StartDocumentImpl(); |
| virtual void EndDocument(); |
| virtual void RenderDone(); |
| virtual void StartElementImpl(HtmlElement* element); |
| virtual void EndElementImpl(HtmlElement* element); |
| virtual void Characters(HtmlCharactersNode* characters); |
| virtual const char* Name() const { return "MobilizeRewrite"; } |
| |
| private: |
| void AppendStylesheet(StringPiece css_file_name, |
| StaticAssetEnum::StaticAsset asset, |
| HtmlElement* element); |
| void AddStyle(HtmlElement* element); |
| MobileRole::Level GetMobileRole(HtmlElement* element); |
| |
| bool CheckForKeyword( |
| const HtmlName::Keyword* sorted_list, int len, HtmlName::Keyword keyword); |
| void LogEncounteredBlock(MobileRole::Level level); |
| GoogleString GetMobJsInitScript(); |
| |
| int body_element_depth_; |
| int keeper_element_depth_; |
| bool reached_reorder_containers_; |
| bool added_viewport_; |
| bool added_style_; |
| bool added_containers_; |
| bool added_progress_; |
| bool added_spacer_; |
| bool config_mode_; |
| bool in_script_; |
| bool saw_end_document_; |
| bool use_js_layout_; |
| bool use_js_nav_; |
| bool labeled_mode_; |
| bool use_static_; |
| bool rewrite_js_; |
| GoogleString static_file_prefix_; |
| |
| // Statistics |
| // Number of web pages we have mobilized. |
| Variable* num_pages_mobilized_; |
| // Number of blocks of each mobile role encountered and reordered. |
| Variable* num_keeper_blocks_; |
| Variable* num_header_blocks_; |
| Variable* num_navigational_blocks_; |
| Variable* num_content_blocks_; |
| Variable* num_marginal_blocks_; |
| // Number of elements deleted. |
| Variable* num_elements_deleted_; |
| |
| // Used for overriding default behavior in testing. |
| friend class MobilizeRewriteFilterTest; |
| |
| DISALLOW_COPY_AND_ASSIGN(MobilizeRewriteFilter); |
| }; |
| |
| } // namespace net_instaweb |
| |
| #endif // NET_INSTAWEB_REWRITER_PUBLIC_MOBILIZE_REWRITE_FILTER_H_ |