blob: 0e05ce9476af3aa9632251220ff7117c796575de [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 "core/css/resolver/FontBuilder.h"
#include "core/CSSValueKeywords.h"
#include "core/dom/Document.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/layout/TextAutosizer.h"
#include "core/style/ComputedStyle.h"
#include "platform/FontFamilyNames.h"
#include "platform/fonts/FontDescription.h"
namespace blink {
FontBuilder::FontBuilder(const Document& document)
: document_(&document), flags_(0) {
DCHECK(document.GetFrame());
}
void FontBuilder::SetInitial(float effective_zoom) {
DCHECK(document_->GetSettings());
if (!document_->GetSettings())
return;
SetFamilyDescription(font_description_,
FontBuilder::InitialFamilyDescription());
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();
case FontDescription::kNoFamily:
return AtomicString();
case FontDescription::kStandardFamily:
return StandardFontFamilyName();
case FontDescription::kSerifFamily:
return FontFamilyNames::webkit_serif;
case FontDescription::kSansSerifFamily:
return FontFamilyNames::webkit_sans_serif;
case FontDescription::kMonospaceFamily:
return FontFamilyNames::webkit_monospace;
case FontDescription::kCursiveFamily:
return FontFamilyNames::webkit_cursive;
case FontDescription::kFantasyFamily:
return FontFamilyNames::webkit_fantasy;
case FontDescription::kPictographFamily:
return FontFamilyNames::webkit_pictograph;
}
}
float FontBuilder::FontSizeForKeyword(unsigned keyword,
bool is_monospace) const {
return FontSize::FontSizeForKeyword(document_, keyword, is_monospace);
}
void FontBuilder::SetFamilyDescription(
const FontDescription::FamilyDescription& family_description) {
SetFamilyDescription(font_description_, family_description);
}
void FontBuilder::SetWeight(FontWeight font_weight) {
Set(PropertySetFlag::kWeight);
font_description_.SetWeight(font_weight);
}
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::SetStretch(FontStretch font_stretch) {
Set(PropertySetFlag::kStretch);
font_description_.SetStretch(font_stretch);
}
void FontBuilder::SetLocale(PassRefPtr<const LayoutLocale> locale) {
Set(PropertySetFlag::kLocale);
font_description_.SetLocale(std::move(locale));
}
void FontBuilder::SetStyle(FontStyle italic) {
Set(PropertySetFlag::kStyle);
font_description_.SetStyle(italic);
}
void FontBuilder::SetVariantCaps(FontDescription::FontVariantCaps caps) {
Set(PropertySetFlag::kVariantCaps);
font_description_.SetVariantCaps(caps);
}
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::SetFontSmoothing(FontSmoothingMode foont_smoothing_mode) {
Set(PropertySetFlag::kFontSmoothing);
font_description_.SetFontSmoothing(foont_smoothing_mode);
}
void FontBuilder::SetFeatureSettings(PassRefPtr<FontFeatureSettings> settings) {
Set(PropertySetFlag::kFeatureSettings);
font_description_.SetFeatureSettings(std::move(settings));
}
void FontBuilder::SetVariationSettings(
PassRefPtr<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) {
float zoom_factor = effective_zoom;
// FIXME: Why is this here!!!!?!
if (LocalFrame* frame = document_->GetFrame())
zoom_factor *= frame->TextZoomFactor();
return FontSize::GetComputedSizeFromSpecifiedSize(
document_, zoom_factor, font_description.IsAbsoluteSize(),
specified_size);
}
static FontOrientation ComputeFontOrientation(const ComputedStyle& style) {
if (style.IsHorizontalWritingMode())
return FontOrientation::kHorizontal;
switch (style.GetTextOrientation()) {
case ETextOrientation::kMixed:
return FontOrientation::kVerticalMixed;
case ETextOrientation::kUpright:
return FontOrientation::kVerticalUpright;
case ETextOrientation::kSideways:
return FontOrientation::kVerticalRotated;
default:
NOTREACHED();
return FontOrientation::kVerticalMixed;
}
}
void FontBuilder::UpdateOrientation(FontDescription& description,
const ComputedStyle& style) {
description.SetOrientation(ComputeFontOrientation(style));
}
void FontBuilder::CheckForGenericFamilyChange(
const FontDescription& old_description,
FontDescription& new_description) {
if (new_description.IsAbsoluteSize())
return;
if (new_description.IsMonospace() == old_description.IsMonospace())
return;
// For now, lump all families but monospace together.
if (new_description.GenericFamily() != FontDescription::kMonospaceFamily &&
old_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 = old_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) {
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);
CheckForGenericFamilyChange(style.GetFontDescription(), 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.Update(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);
float multiplier = style.TextAutosizingMultiplier();
adjusted_size =
TextAutosizer::ComputeAutosizedFontSize(adjusted_size, multiplier);
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());
float multiplier = style.TextAutosizingMultiplier();
computed_size =
TextAutosizer::ComputeAutosizedFontSize(computed_size, multiplier);
font_description.SetComputedSize(computed_size);
}
void FontBuilder::CreateFont(FontSelector* font_selector,
ComputedStyle& style) {
if (!flags_)
return;
FontDescription description = style.GetFontDescription();
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::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::kFontSmoothing))
description.SetFontSmoothing(font_description_.FontSmoothing());
if (IsSet(PropertySetFlag::kTextOrientation) ||
IsSet(PropertySetFlag::kWritingMode))
UpdateOrientation(description, style);
UpdateSpecifiedSize(description, style);
UpdateComputedSize(description, style);
UpdateAdjustedSize(description, style, font_selector);
style.SetFontDescription(description);
style.GetFont().Update(font_selector);
flags_ = 0;
}
void FontBuilder::CreateFontForDocument(FontSelector* font_selector,
ComputedStyle& document_style) {
FontDescription font_description = FontDescription();
font_description.SetLocale(document_style.GetFontDescription().Locale());
SetFamilyDescription(font_description,
FontBuilder::InitialFamilyDescription());
SetSize(font_description,
FontDescription::Size(FontSize::InitialKeywordSize(), 0.0f, false));
UpdateSpecifiedSize(font_description, document_style);
UpdateComputedSize(font_description, document_style);
UpdateOrientation(font_description, document_style);
document_style.SetFontDescription(font_description);
document_style.GetFont().Update(font_selector);
}
} // namespace blink