blob: 4bd563a1b1fd32c8c440082d9889fc1ff561365f [file] [log] [blame]
/*
* Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
* (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/css/css_font_selector.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/core/animation/interpolable_color.h"
#include "third_party/blink/renderer/core/css/css_segmented_font_face.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/font_face_set_document.h"
#include "third_party/blink/renderer/core/css/font_size_functions.h"
#include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_engine.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/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/fonts/font_selector_client.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
namespace {
scoped_refptr<FontPalette> RetrieveFontPaletteFromStyleEngine(
scoped_refptr<const FontPalette> request_palette,
StyleEngine& style_engine,
const AtomicString& family_name) {
AtomicString requested_palette_values =
request_palette->GetPaletteValuesName();
StyleRuleFontPaletteValues* font_palette_values =
style_engine.FontPaletteValuesForNameAndFamily(requested_palette_values,
family_name);
if (font_palette_values) {
scoped_refptr<FontPalette> new_request_palette =
FontPalette::Create(requested_palette_values);
new_request_palette->SetMatchFamilyName(family_name);
new_request_palette->SetBasePalette(
font_palette_values->GetBasePaletteIndex());
Vector<FontPalette::FontPaletteOverride> override_colors =
font_palette_values->GetOverrideColorsAsVector();
if (override_colors.size()) {
new_request_palette->SetColorOverrides(std::move(override_colors));
}
return new_request_palette;
}
return nullptr;
}
scoped_refptr<const FontPalette> ResolveInterpolableFontPalette(
scoped_refptr<const FontPalette> font_palette,
StyleEngine& style_engine,
const AtomicString& family_name) {
if (!font_palette->IsInterpolablePalette()) {
if (font_palette->IsCustomPalette()) {
scoped_refptr<FontPalette> retrieved_palette =
RetrieveFontPaletteFromStyleEngine(font_palette, style_engine,
family_name);
return retrieved_palette ? retrieved_palette : FontPalette::Create();
} else {
return font_palette;
}
}
scoped_refptr<const FontPalette> start_palette =
ResolveInterpolableFontPalette(font_palette->GetStart(), style_engine,
family_name);
scoped_refptr<const FontPalette> end_palette = ResolveInterpolableFontPalette(
font_palette->GetEnd(), style_engine, family_name);
// If two endpoints of the interpolation are equal, we can simplify the tree
if (*start_palette.get() == *end_palette.get()) {
return start_palette;
}
scoped_refptr<FontPalette> new_palette;
new_palette = FontPalette::Mix(
start_palette, end_palette, font_palette->GetStartPercentage(),
font_palette->GetEndPercentage(), font_palette->GetNormalizedPercentage(),
font_palette->GetAlphaMultiplier(),
font_palette->GetColorInterpolationSpace(),
font_palette->GetHueInterpolationMethod());
return new_palette;
}
} // namespace
CSSFontSelector::CSSFontSelector(const TreeScope& tree_scope)
: tree_scope_(&tree_scope) {
DCHECK(tree_scope.GetDocument().GetExecutionContext()->IsContextThread());
DCHECK(tree_scope.GetDocument().GetFrame());
generic_font_family_settings_ = tree_scope.GetDocument()
.GetFrame()
->GetSettings()
->GetGenericFontFamilySettings();
FontCache::Get().AddClient(this);
if (tree_scope.RootNode().IsDocumentNode()) {
font_face_cache_ = MakeGarbageCollected<FontFaceCache>();
FontFaceSetDocument::From(tree_scope.GetDocument())
->AddFontFacesToFontFaceCache(font_face_cache_);
}
}
CSSFontSelector::~CSSFontSelector() = default;
UseCounter* CSSFontSelector::GetUseCounter() const {
auto* const context = GetExecutionContext();
return context && context->IsContextThread() ? context : nullptr;
}
void CSSFontSelector::RegisterForInvalidationCallbacks(
FontSelectorClient* client) {
CHECK(client);
clients_.insert(client);
}
void CSSFontSelector::UnregisterForInvalidationCallbacks(
FontSelectorClient* client) {
clients_.erase(client);
}
void CSSFontSelector::DispatchInvalidationCallbacks(
FontInvalidationReason reason) {
font_face_cache_->IncrementVersion();
HeapVector<Member<FontSelectorClient>> clients(clients_);
for (auto& client : clients) {
if (client) {
client->FontsNeedUpdate(this, reason);
}
}
}
void CSSFontSelector::FontFaceInvalidated(FontInvalidationReason reason) {
DispatchInvalidationCallbacks(reason);
}
void CSSFontSelector::FontCacheInvalidated() {
DispatchInvalidationCallbacks(FontInvalidationReason::kGeneralInvalidation);
}
const FontData* CSSFontSelector::GetFontData(
const FontDescription& font_description,
const FontFamily& font_family) {
const auto& family_name = font_family.FamilyName();
Document& document = GetTreeScope()->GetDocument();
FontDescription request_description(font_description);
const FontPalette* request_palette = request_description.GetFontPalette();
if (request_palette && request_palette->IsCustomPalette()) {
scoped_refptr<FontPalette> new_request_palette =
RetrieveFontPaletteFromStyleEngine(
request_palette, document.GetStyleEngine(), family_name);
if (new_request_palette) {
request_description.SetFontPalette(new_request_palette);
}
}
if (RuntimeEnabledFeatures::FontPaletteAnimationEnabled() &&
request_palette && request_palette->IsInterpolablePalette()) {
scoped_refptr<const FontPalette> computed_interpolable_palette =
ResolveInterpolableFontPalette(request_palette,
document.GetStyleEngine(), family_name);
request_description.SetFontPalette(computed_interpolable_palette);
}
if (request_description.GetFontVariantAlternates()) {
// TODO(https://crbug.com/1382722): For scoping to work correctly, we'd need
// to traverse the TreeScopes here and fuse / override values of
// @font-feature-values from these.
const FontFeatureValuesStorage* feature_values_storage =
document.GetScopedStyleResolver()
? document.GetScopedStyleResolver()->FontFeatureValuesForFamily(
family_name)
: nullptr;
scoped_refptr<FontVariantAlternates> new_alternates = nullptr;
if (feature_values_storage) {
new_alternates = request_description.GetFontVariantAlternates()->Resolve(
[feature_values_storage](AtomicString alias) {
return feature_values_storage->ResolveStylistic(alias);
},
[feature_values_storage](AtomicString alias) {
return feature_values_storage->ResolveStyleset(alias);
},
[feature_values_storage](AtomicString alias) {
return feature_values_storage->ResolveCharacterVariant(alias);
},
[feature_values_storage](AtomicString alias) {
return feature_values_storage->ResolveSwash(alias);
},
[feature_values_storage](AtomicString alias) {
return feature_values_storage->ResolveOrnaments(alias);
},
[feature_values_storage](AtomicString alias) {
return feature_values_storage->ResolveAnnotation(alias);
});
} else {
// If no StyleRuleFontFeature alias table values for this font was found,
// it still needs a resolve call to convert historical-forms state (which
// is not looked-up against StyleRuleFontFeatureValues) to an internal
// feature.
auto no_lookup = [](AtomicString) -> Vector<uint32_t> { return {}; };
new_alternates = request_description.GetFontVariantAlternates()->Resolve(
no_lookup, no_lookup, no_lookup, no_lookup, no_lookup, no_lookup);
}
if (new_alternates) {
request_description.SetFontVariantAlternates(new_alternates);
}
}
if (!font_family.FamilyIsGeneric()) {
if (CSSSegmentedFontFace* face =
font_face_cache_->Get(request_description, family_name)) {
return face->GetFontData(request_description);
}
}
// Try to return the correct font based off our settings, in case we were
// handed the generic font family name.
AtomicString settings_family_name =
FamilyNameFromSettings(request_description, font_family);
if (settings_family_name.empty()) {
return nullptr;
}
ReportFontFamilyLookupByGenericFamily(
family_name, request_description.GetScript(),
request_description.GenericFamily(), settings_family_name);
const SimpleFontData* font_data =
FontCache::Get().GetFontData(request_description, settings_family_name);
if (font_data && request_description.HasSizeAdjust()) {
DCHECK(RuntimeEnabledFeatures::CSSFontSizeAdjustEnabled());
if (auto adjusted_size =
FontSizeFunctions::MetricsMultiplierAdjustedFontSize(
font_data, request_description)) {
FontDescription size_adjusted_description(request_description);
size_adjusted_description.SetAdjustedSize(adjusted_size.value());
font_data = FontCache::Get().GetFontData(size_adjusted_description,
settings_family_name);
}
}
ReportFontLookupByUniqueOrFamilyName(settings_family_name,
request_description, font_data);
return font_data;
}
void CSSFontSelector::UpdateGenericFontFamilySettings(Document& document) {
if (!document.GetSettings()) {
return;
}
generic_font_family_settings_ =
document.GetSettings()->GetGenericFontFamilySettings();
FontCacheInvalidated();
}
FontMatchingMetrics* CSSFontSelector::GetFontMatchingMetrics() const {
return GetDocument().GetFontMatchingMetrics();
}
bool CSSFontSelector::IsAlive() const {
return tree_scope_ != nullptr;
}
void CSSFontSelector::Trace(Visitor* visitor) const {
visitor->Trace(tree_scope_);
visitor->Trace(clients_);
CSSFontSelectorBase::Trace(visitor);
}
} // namespace blink