| /* |
| * 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 |