blob: a759bfdc53d1ebc9025c04afa1c95dd7e006c0c8 [file] [log] [blame]
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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/platform/fonts/font_fallback_list.h"
#include "third_party/blink/renderer/platform/font_family_names.h"
#include "third_party/blink/renderer/platform/fonts/alternate_font_family.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/fonts/font_cache_key.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/fonts/font_fallback_map.h"
#include "third_party/blink/renderer/platform/fonts/font_family.h"
#include "third_party/blink/renderer/platform/fonts/segmented_font_data.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
namespace blink {
FontFallbackList::FontFallbackList(FontFallbackMap& font_fallback_map)
: cached_primary_simple_font_data_(nullptr),
font_fallback_map_(font_fallback_map),
family_index_(0),
generation_(FontCache::GetFontCache()->Generation()),
has_loading_fallback_(false),
has_custom_font_(false),
has_advance_override_(false),
can_shape_word_by_word_(false),
can_shape_word_by_word_computed_(false),
is_invalid_(false) {}
FontFallbackList::~FontFallbackList() {
ReleaseFontData();
}
FontSelector* FontFallbackList::GetFontSelector() const {
// FontFallbackList objects are managed in FontFallbackMap, and should not be
// used after FontFallbackMap is destroyed.
DCHECK(font_fallback_map_);
return font_fallback_map_->GetFontSelector();
}
void FontFallbackList::ReleaseFontData() {
unsigned num_fonts = font_list_.size();
for (unsigned i = 0; i < num_fonts; ++i) {
if (!font_list_[i]->IsCustomFont()) {
DCHECK(!font_list_[i]->IsSegmented());
FontCache::GetFontCache()->ReleaseFontData(
To<SimpleFontData>(font_list_[i].get()));
}
}
shape_cache_.reset(); // Clear the weak pointer to the cache instance.
}
bool FontFallbackList::ShouldSkipDrawing() const {
// The DCHECK hit will be fixed by the runtime enabled feature below, so we
// don't fix it in the legacy code paths.
DCHECK(IsValid());
if (!has_loading_fallback_)
return false;
unsigned num_fonts = font_list_.size();
for (unsigned i = 0; i < num_fonts; ++i) {
if (font_list_[i]->ShouldSkipDrawing())
return true;
}
return false;
}
const SimpleFontData* FontFallbackList::DeterminePrimarySimpleFontData(
const FontDescription& font_description) {
bool should_load_custom_font = true;
for (unsigned font_index = 0;; ++font_index) {
const FontData* font_data = FontDataAt(font_description, font_index);
if (!font_data) {
// All fonts are custom fonts and are loading. Return the first FontData.
font_data = FontDataAt(font_description, 0);
if (font_data)
return font_data->FontDataForCharacter(kSpaceCharacter);
FontCache* cache = FontCache::GetFontCache();
SimpleFontData* last_resort_fallback =
cache->GetLastResortFallbackFont(font_description).get();
DCHECK(last_resort_fallback);
return last_resort_fallback;
}
const auto* segmented = DynamicTo<SegmentedFontData>(font_data);
if (segmented && !segmented->ContainsCharacter(kSpaceCharacter))
continue;
const SimpleFontData* font_data_for_space =
font_data->FontDataForCharacter(kSpaceCharacter);
DCHECK(font_data_for_space);
// When a custom font is loading, we should use the correct fallback font to
// layout the text. Here skip the temporary font for the loading custom
// font which may not act as the correct fallback font.
if (!font_data_for_space->IsLoadingFallback())
return font_data_for_space;
if (segmented) {
for (unsigned i = 0; i < segmented->NumFaces(); i++) {
const SimpleFontData* range_font_data =
segmented->FaceAt(i)->FontData();
if (!range_font_data->IsLoadingFallback())
return range_font_data;
}
if (font_data->IsLoading())
should_load_custom_font = false;
}
// Begin to load the first custom font if needed.
if (should_load_custom_font) {
should_load_custom_font = false;
font_data_for_space->GetCustomFontData()->BeginLoadIfNeeded();
}
}
}
scoped_refptr<FontData> FontFallbackList::GetFontData(
const FontDescription& font_description) {
const FontFamily* curr_family = &font_description.Family();
for (int i = 0; curr_family && i < family_index_; i++)
curr_family = curr_family->Next();
for (; curr_family; curr_family = curr_family->Next()) {
family_index_++;
if (curr_family->Family().length()) {
scoped_refptr<FontData> result;
if (GetFontSelector()) {
result = GetFontSelector()->GetFontData(font_description,
curr_family->Family());
}
if (!result) {
result = FontCache::GetFontCache()->GetFontData(font_description,
curr_family->Family());
if (GetFontSelector()) {
GetFontSelector()->ReportFontLookupByUniqueOrFamilyName(
curr_family->Family(), font_description,
DynamicTo<SimpleFontData>(result.get()));
}
}
if (result) {
if (GetFontSelector()) {
GetFontSelector()->ReportSuccessfulFontFamilyMatch(
curr_family->Family());
}
return result;
}
if (GetFontSelector())
GetFontSelector()->ReportFailedFontFamilyMatch(curr_family->Family());
}
}
family_index_ = kCAllFamiliesScanned;
if (GetFontSelector()) {
// Try the user's preferred standard font.
if (scoped_refptr<FontData> data = GetFontSelector()->GetFontData(
font_description, font_family_names::kWebkitStandard))
return data;
}
// Still no result. Hand back our last resort fallback font.
auto last_resort =
FontCache::GetFontCache()->GetLastResortFallbackFont(font_description);
if (GetFontSelector()) {
GetFontSelector()->ReportLastResortFallbackFontLookup(font_description,
last_resort.get());
}
return last_resort;
}
FallbackListCompositeKey FontFallbackList::CompositeKey(
const FontDescription& font_description) const {
FallbackListCompositeKey key(font_description);
const FontFamily* current_family = &font_description.Family();
while (current_family) {
if (current_family->Family().length()) {
FontFaceCreationParams params(
AdjustFamilyNameToAvoidUnsupportedFonts(current_family->Family()));
scoped_refptr<FontData> result;
if (GetFontSelector()) {
result = GetFontSelector()->GetFontData(font_description,
current_family->Family());
}
if (!result) {
if (FontPlatformData* platform_data =
FontCache::GetFontCache()->GetFontPlatformData(font_description,
params))
result = FontCache::GetFontCache()->FontDataFromFontPlatformData(
platform_data);
}
if (result) {
bool is_unique_match = false;
key.Add(font_description.CacheKey(params, is_unique_match));
auto* font_data = DynamicTo<SimpleFontData>(result.get());
if (!font_data && !result->IsCustomFont())
FontCache::GetFontCache()->ReleaseFontData(font_data);
}
}
current_family = current_family->Next();
}
return key;
}
const FontData* FontFallbackList::FontDataAt(
const FontDescription& font_description,
unsigned realized_font_index) {
// This fallback font is already in our list.
if (realized_font_index < font_list_.size())
return font_list_[realized_font_index].get();
// Make sure we're not passing in some crazy value here.
DCHECK_EQ(realized_font_index, font_list_.size());
if (family_index_ == kCAllFamiliesScanned)
return nullptr;
// Ask the font cache for the font data.
// We are obtaining this font for the first time. We keep track of the
// families we've looked at before in |family_index_|, so that we never scan
// the same spot in the list twice. GetFontData will adjust our
// |family_index_| as it scans for the right font to make.
DCHECK_EQ(FontCache::GetFontCache()->Generation(), generation_);
scoped_refptr<FontData> result = GetFontData(font_description);
if (result) {
font_list_.push_back(result);
if (result->IsLoadingFallback())
has_loading_fallback_ = true;
if (result->IsCustomFont())
has_custom_font_ = true;
if (result->HasAdvanceOverride())
has_advance_override_ = true;
}
return result.get();
}
bool FontFallbackList::ComputeCanShapeWordByWord(
const FontDescription& font_description) {
if (!font_description.GetTypesettingFeatures())
return true;
const SimpleFontData* primary_font = PrimarySimpleFontData(font_description);
if (!primary_font)
return false;
const FontPlatformData& platform_data = primary_font->PlatformData();
TypesettingFeatures features = font_description.GetTypesettingFeatures();
return !platform_data.HasSpaceInLigaturesOrKerning(features);
}
bool FontFallbackList::CanShapeWordByWord(
const FontDescription& font_description) {
if (!can_shape_word_by_word_computed_) {
can_shape_word_by_word_ = ComputeCanShapeWordByWord(font_description);
can_shape_word_by_word_computed_ = true;
}
return can_shape_word_by_word_;
}
} // namespace blink