blob: a276cc413722250894a7f4f2298a043cda6a9a9d [file] [log] [blame]
/*
* Copyright 2015 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: jmaessen@google.com (Jan-Willem Maessen)
#include "net/instaweb/rewriter/public/mobilize_filter_base.h"
#include <algorithm>
#include "base/logging.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 "pagespeed/kernel/base/basictypes.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"
namespace net_instaweb {
namespace {
const HtmlName::Keyword kKeeperTags[] = {
HtmlName::kArea, HtmlName::kLink, HtmlName::kMap, HtmlName::kMeta,
HtmlName::kScript, HtmlName::kStyle, HtmlName::kTitle};
const int kNumKeeperTags = arraysize(kKeeperTags);
#ifndef NDEBUG
// For invariant-checking the static data above.
void CheckKeepersSorted() {
for (int i = 1; i < kNumKeeperTags; ++i) {
DCHECK_LT(kKeeperTags[i - 1], kKeeperTags[i]);
}
}
#endif // #ifndef NDEBUG
} // namespace
const MobileRoleData MobileRoleData::kMobileRoles[MobileRole::kInvalid] = {
MobileRoleData(MobileRole::kKeeper, "keeper"),
MobileRoleData(MobileRole::kHeader, "header"),
MobileRoleData(MobileRole::kNavigational, "navigational"),
MobileRoleData(MobileRole::kContent, "content"),
MobileRoleData(MobileRole::kMarginal, "marginal")
};
const MobileRoleData* MobileRoleData::FromString(StringPiece mobile_role) {
for (int i = 0, n = arraysize(kMobileRoles); i < n; ++i) {
if (mobile_role == kMobileRoles[i].value) {
return &kMobileRoles[i];
}
}
return NULL;
}
MobileRole::Level MobileRoleData::LevelFromString(StringPiece mobile_role) {
const MobileRoleData* role = FromString(mobile_role);
if (role == NULL) {
return MobileRole::kInvalid;
} else {
return role->level;
}
}
bool MobilizeFilterBase::IsKeeperTag(HtmlName::Keyword tag) {
return std::binary_search(kKeeperTags, kKeeperTags + kNumKeeperTags, tag);
}
MobilizeFilterBase::MobilizeFilterBase(RewriteDriver* driver)
: CommonFilter(driver),
active_skip_element_(NULL) {
#ifndef NDEBUG
CheckKeepersSorted();
#endif // #ifndef NDEBUG
}
MobilizeFilterBase::~MobilizeFilterBase() {
DCHECK(!AreInSkip());
}
void MobilizeFilterBase::StartElementImpl(HtmlElement* element) {
if (AreInSkip()) {
return;
}
if (IsKeeperTag(element->keyword())) {
// Ignore content in things like <script> and <style> blocks that
// don't contain user-accessible content.
active_skip_element_ = element;
return;
}
HtmlElement::Attribute* mobile_role_attribute =
element->FindAttribute(HtmlName::kDataMobileRole);
MobileRole::Level role =
mobile_role_attribute == NULL ? MobileRole::kUnassigned :
MobileRoleData::LevelFromString(mobile_role_attribute->escaped_value());
StartNonSkipElement(role, element);
}
void MobilizeFilterBase::EndElementImpl(HtmlElement* element) {
if (AreInSkip()) {
if (active_skip_element_ == element) {
active_skip_element_ = NULL;
}
return;
}
EndNonSkipElement(element);
}
void MobilizeFilterBase::EndDocument() {
EndDocumentImpl();
DCHECK(active_skip_element_ == NULL);
active_skip_element_ = NULL;
}
} // namespace net_instaweb