blob: 2a4b1aa50b928b8ef63cb10f3168370fd5d7b719 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
* All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
* Copyright (C) 2015 Collabora Ltd. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "third_party/blink/renderer/core/css/resolver/font_builder.h"
#include "third_party/blink/renderer/core/css/css_font_selector.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
namespace blink {
FontBuilder::FontBuilder(Document* document) : document_(document) {
DCHECK(!document || document->GetFrame());
}
void FontBuilder::SetInitial(float effective_zoom) {
DCHECK(document_->GetSettings());
if (!document_->GetSettings())
return;
SetFamilyDescription(font_description_,
FontBuilder::InitialFamilyDescription());
SetFamilyTreeScope(nullptr);
SetSize(font_description_, FontBuilder::InitialSize());
}
void FontBuilder::DidChangeEffectiveZoom() {
Set(PropertySetFlag::kEffectiveZoom);
}
void FontBuilder::DidChangeTextOrientation() {
Set(PropertySetFlag::kTextOrientation);
}
void FontBuilder::DidChangeWritingMode() {
Set(PropertySetFlag::kWritingMode);
}
FontFamily FontBuilder::StandardFontFamily() const {
FontFamily family;
family.SetFamily(StandardFontFamilyName());
return family;
}
AtomicString FontBuilder::StandardFontFamilyName() const {
Settings* settings = document_->GetSettings();
if (settings)
return settings->GetGenericFontFamilySettings().Standard();
return AtomicString();
}
AtomicString FontBuilder::GenericFontFamilyName(
FontDescription::GenericFamilyType generic_family) const {
switch (generic_family) {
default:
NOTREACHED();
FALLTHROUGH;
case FontDescription::kNoFamily:
return AtomicString();
case FontDescription::kStandardFamily:
return StandardFontFamilyName();
case FontDescription::kSerifFamily:
return font_family_names::kWebkitSerif;
case FontDescription::kSansSerifFamily:
return font_family_names::kWebkitSansSerif;
case FontDescription::kMonospaceFamily:
return font_family_names::kWebkitMonospace;
case FontDescription::kCursiveFamily:
return font_family_names::kWebkitCursive;
case FontDescription::kFantasyFamily:
return font_family_names::kWebkitFantasy;
}
}
float FontBuilder::FontSizeForKeyword(unsigned keyword,
bool is_monospace) const {
return FontSizeFunctions::FontSizeForKeyword(document_, keyword,
is_monospace);
}
void FontBuilder::SetFamilyDescription(
const FontDescription::FamilyDescription& family_description) {
SetFamilyDescription(font_description_, family_description);
}
void FontBuilder::SetFamilyTreeScope(const TreeScope* tree_scope) {
family_tree_scope_ = tree_scope;
}
void FontBuilder::SetWeight(FontSelectionValue weight) {
Set(PropertySetFlag::kWeight);
font_description_.SetWeight(weight);
}
void FontBuilder::SetStyle(FontSelectionValue slope) {
Set(PropertySetFlag::kStyle);
font_description_.SetStyle(slope);
}
void FontBuilder::SetStretch(FontSelectionValue stretch) {
Set(PropertySetFlag::kStretch);
font_description_.SetStretch(stretch);
}
void FontBuilder::SetSize(const FontDescription::Size& size) {
SetSize(font_description_, size);
}
void FontBuilder::SetSizeAdjust(float aspect_value) {
Set(PropertySetFlag::kSizeAdjust);
font_description_.SetSizeAdjust(aspect_value);
}
void FontBuilder::SetLocale(scoped_refptr<const LayoutLocale> locale) {
Set(PropertySetFlag::kLocale);
font_description_.SetLocale(std::move(locale));
}
void FontBuilder::SetVariantCaps(FontDescription::FontVariantCaps caps) {
Set(PropertySetFlag::kVariantCaps);
font_description_.SetVariantCaps(caps);
}
void FontBuilder::SetVariantEastAsian(const FontVariantEastAsian east_asian) {
Set(PropertySetFlag::kVariantEastAsian);
font_description_.SetVariantEastAsian(east_asian);
}
void FontBuilder::SetVariantLigatures(
const FontDescription::VariantLigatures& ligatures) {
Set(PropertySetFlag::kVariantLigatures);
font_description_.SetVariantLigatures(ligatures);
}
void FontBuilder::SetVariantNumeric(const FontVariantNumeric& variant_numeric) {
Set(PropertySetFlag::kVariantNumeric);
font_description_.SetVariantNumeric(variant_numeric);
}
void FontBuilder::SetTextRendering(TextRenderingMode text_rendering_mode) {
Set(PropertySetFlag::kTextRendering);
font_description_.SetTextRendering(text_rendering_mode);
}
void FontBuilder::SetKerning(FontDescription::Kerning kerning) {
Set(PropertySetFlag::kKerning);
font_description_.SetKerning(kerning);
}
void FontBuilder::SetFontOpticalSizing(OpticalSizing font_optical_sizing) {
Set(PropertySetFlag::kFontOpticalSizing);
font_description_.SetFontOpticalSizing(font_optical_sizing);
}
void FontBuilder::SetFontSmoothing(FontSmoothingMode foont_smoothing_mode) {
Set(PropertySetFlag::kFontSmoothing);
font_description_.SetFontSmoothing(foont_smoothing_mode);
}
void FontBuilder::SetFeatureSettings(
scoped_refptr<FontFeatureSettings> settings) {
Set(PropertySetFlag::kFeatureSettings);
font_description_.SetFeatureSettings(std::move(settings));
}
void FontBuilder::SetVariationSettings(
scoped_refptr<FontVariationSettings> settings) {
Set(PropertySetFlag::kVariationSettings);
font_description_.SetVariationSettings(std::move(settings));
}
void FontBuilder::SetFamilyDescription(
FontDescription& font_description,
const FontDescription::FamilyDescription& family_description) {
Set(PropertySetFlag::kFamily);
bool is_initial =
family_description.generic_family == FontDescription::kStandardFamily &&
family_description.family.FamilyIsEmpty();
font_description.SetGenericFamily(family_description.generic_family);
font_description.SetFamily(is_initial ? StandardFontFamily()
: family_description.family);
}
void FontBuilder::SetSize(FontDescription& font_description,
const FontDescription::Size& size) {
float specified_size = size.value;
if (specified_size < 0)
return;
Set(PropertySetFlag::kSize);
// Overly large font sizes will cause crashes on some platforms (such as
// Windows). Cap font size here to make sure that doesn't happen.
specified_size = std::min(kMaximumAllowedFontSize, specified_size);
font_description.SetKeywordSize(size.keyword);
font_description.SetSpecifiedSize(specified_size);
font_description.SetIsAbsoluteSize(size.is_absolute);
}
float FontBuilder::GetComputedSizeFromSpecifiedSize(
FontDescription& font_description,
float effective_zoom,
float specified_size) {
DCHECK(document_);
float zoom_factor = effective_zoom;
// Apply the text zoom factor preference. The preference is exposed in
// accessibility settings in Chrome for Android to improve readability.
if (LocalFrame* frame = document_->GetFrame())
zoom_factor *= frame->TextZoomFactor();
return FontSizeFunctions::GetComputedSizeFromSpecifiedSize(
document_, zoom_factor, font_description.IsAbsoluteSize(),
specified_size);
}
void FontBuilder::CheckForGenericFamilyChange(
const FontDescription& parent_description,
FontDescription& new_description) {
DCHECK(document_);
if (new_description.IsAbsoluteSize())
return;
if (new_description.IsMonospace() == parent_description.IsMonospace())
return;
// For now, lump all families but monospace together.
if (new_description.GenericFamily() != FontDescription::kMonospaceFamily &&
parent_description.GenericFamily() != FontDescription::kMonospaceFamily)
return;
// We know the parent is monospace or the child is monospace, and that font
// size was unspecified. We want to scale our font size as appropriate.
// If the font uses a keyword size, then we refetch from the table rather than
// multiplying by our scale factor.
float size;
if (new_description.KeywordSize()) {
size = FontSizeForKeyword(new_description.KeywordSize(),
new_description.IsMonospace());
} else {
Settings* settings = document_->GetSettings();
float fixed_scale_factor =
(settings && settings->GetDefaultFixedFontSize() &&
settings->GetDefaultFontSize())
? static_cast<float>(settings->GetDefaultFixedFontSize()) /
settings->GetDefaultFontSize()
: 1;
size = parent_description.IsMonospace()
? new_description.SpecifiedSize() / fixed_scale_factor
: new_description.SpecifiedSize() * fixed_scale_factor;
}
new_description.SetSpecifiedSize(size);
}
void FontBuilder::UpdateSpecifiedSize(FontDescription& font_description,
const ComputedStyle& style,
const ComputedStyle* parent_style) {
float specified_size = font_description.SpecifiedSize();
if (!specified_size && font_description.KeywordSize())
specified_size = FontSizeForKeyword(font_description.KeywordSize(),
font_description.IsMonospace());
font_description.SetSpecifiedSize(specified_size);
// TODO(crbug.com/1086680): Avoid nullptr parent style.
const FontDescription& parent_description =
parent_style ? parent_style->GetFontDescription()
: style.GetFontDescription();
CheckForGenericFamilyChange(parent_description, font_description);
}
void FontBuilder::UpdateAdjustedSize(FontDescription& font_description,
const ComputedStyle& style,
FontSelector* font_selector) {
const float specified_size = font_description.SpecifiedSize();
if (!font_description.HasSizeAdjust() || !specified_size)
return;
// We need to create a temporal Font to get xHeight of a primary font.
// The aspect value is based on the xHeight of the font for the computed font
// size, so we need to reset the adjustedSize to computedSize. See
// FontDescription::EffectiveFontSize.
font_description.SetAdjustedSize(font_description.ComputedSize());
Font font(font_description, font_selector);
const SimpleFontData* font_data = font.PrimaryFont();
if (!font_data || !font_data->GetFontMetrics().HasXHeight())
return;
const float size_adjust = font_description.SizeAdjust();
float aspect_value = font_data->GetFontMetrics().XHeight() / specified_size;
float adjusted_size = (size_adjust / aspect_value) * specified_size;
adjusted_size = GetComputedSizeFromSpecifiedSize(
font_description, style.EffectiveZoom(), adjusted_size);
adjusted_size = TextAutosizer::ComputeAutosizedFontSize(
adjusted_size, style.TextAutosizingMultiplier(), style.EffectiveZoom());
font_description.SetAdjustedSize(adjusted_size);
}
void FontBuilder::UpdateComputedSize(FontDescription& font_description,
const ComputedStyle& style) {
float computed_size =
GetComputedSizeFromSpecifiedSize(font_description, style.EffectiveZoom(),
font_description.SpecifiedSize());
computed_size = TextAutosizer::ComputeAutosizedFontSize(
computed_size, style.TextAutosizingMultiplier(), style.EffectiveZoom());
font_description.SetComputedSize(computed_size);
}
void FontBuilder::UpdateFontDescription(FontDescription& description,
FontOrientation font_orientation) {
if (IsSet(PropertySetFlag::kFamily)) {
description.SetGenericFamily(font_description_.GenericFamily());
description.SetFamily(font_description_.Family());
}
if (IsSet(PropertySetFlag::kSize)) {
description.SetKeywordSize(font_description_.KeywordSize());
description.SetSpecifiedSize(font_description_.SpecifiedSize());
description.SetIsAbsoluteSize(font_description_.IsAbsoluteSize());
}
if (IsSet(PropertySetFlag::kSizeAdjust))
description.SetSizeAdjust(font_description_.SizeAdjust());
if (IsSet(PropertySetFlag::kWeight))
description.SetWeight(font_description_.Weight());
if (IsSet(PropertySetFlag::kStretch))
description.SetStretch(font_description_.Stretch());
if (IsSet(PropertySetFlag::kFeatureSettings))
description.SetFeatureSettings(font_description_.FeatureSettings());
if (IsSet(PropertySetFlag::kLocale))
description.SetLocale(font_description_.Locale());
if (IsSet(PropertySetFlag::kStyle))
description.SetStyle(font_description_.Style());
if (IsSet(PropertySetFlag::kVariantCaps))
description.SetVariantCaps(font_description_.VariantCaps());
if (IsSet(PropertySetFlag::kVariantEastAsian))
description.SetVariantEastAsian(font_description_.VariantEastAsian());
if (IsSet(PropertySetFlag::kVariantLigatures))
description.SetVariantLigatures(font_description_.GetVariantLigatures());
if (IsSet(PropertySetFlag::kVariantNumeric))
description.SetVariantNumeric(font_description_.VariantNumeric());
if (IsSet(PropertySetFlag::kVariationSettings))
description.SetVariationSettings(font_description_.VariationSettings());
if (IsSet(PropertySetFlag::kTextRendering))
description.SetTextRendering(font_description_.TextRendering());
if (IsSet(PropertySetFlag::kKerning))
description.SetKerning(font_description_.GetKerning());
if (IsSet(PropertySetFlag::kFontOpticalSizing))
description.SetFontOpticalSizing(font_description_.FontOpticalSizing());
if (IsSet(PropertySetFlag::kFontSmoothing))
description.SetFontSmoothing(font_description_.FontSmoothing());
if (IsSet(PropertySetFlag::kTextOrientation) ||
IsSet(PropertySetFlag::kWritingMode))
description.SetOrientation(font_orientation);
float size = description.SpecifiedSize();
if (!size && description.KeywordSize()) {
size = FontSizeForKeyword(description.KeywordSize(),
description.IsMonospace());
}
description.SetSpecifiedSize(size);
description.SetComputedSize(size);
if (size && description.HasSizeAdjust())
description.SetAdjustedSize(size);
}
FontSelector* FontBuilder::FontSelectorFromTreeScope(
const TreeScope* tree_scope) {
// TODO(crbug.com/437837): The tree_scope may be from a different Document in
// the case where we are resolving style for elements in a <svg:use> shadow
// tree.
DCHECK(!tree_scope || tree_scope->GetDocument() == document_ ||
tree_scope->GetDocument().IsSVGDocument());
// TODO(crbug.com/336876): Font selector should be based on tree_scope for
// tree-scoped references.
return document_->GetStyleEngine().GetFontSelector();
}
FontSelector* FontBuilder::ComputeFontSelector(const ComputedStyle& style) {
if (IsSet(PropertySetFlag::kFamily))
return FontSelectorFromTreeScope(family_tree_scope_);
else
return style.GetFont().GetFontSelector();
}
void FontBuilder::CreateFont(ComputedStyle& style,
const ComputedStyle* parent_style) {
DCHECK(document_);
if (!flags_)
return;
FontDescription description = style.GetFontDescription();
UpdateFontDescription(description, style.ComputeFontOrientation());
UpdateSpecifiedSize(description, style, parent_style);
UpdateComputedSize(description, style);
FontSelector* font_selector = ComputeFontSelector(style);
UpdateAdjustedSize(description, style, font_selector);
style.SetFontInternal(Font(description, font_selector));
flags_ = 0;
}
void FontBuilder::CreateFontForDocument(ComputedStyle& document_style) {
DCHECK(document_);
FontDescription font_description = FontDescription();
font_description.SetLocale(document_style.GetFontDescription().Locale());
SetFamilyDescription(font_description,
FontBuilder::InitialFamilyDescription());
SetSize(font_description,
FontDescription::Size(FontSizeFunctions::InitialKeywordSize(), 0.0f,
false));
UpdateSpecifiedSize(font_description, document_style, &document_style);
UpdateComputedSize(font_description, document_style);
font_description.SetOrientation(document_style.ComputeFontOrientation());
FontSelector* font_selector = document_->GetStyleEngine().GetFontSelector();
document_style.SetFontInternal(Font(font_description, font_selector));
}
} // namespace blink