blob: e73b0eeb0a1a890217ecd163a795fed791edcbe8 [file] [log] [blame]
/*
* Copyright (C) 2008 Apple 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.
*
* 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 "core/css/CSSSegmentedFontFace.h"
#include "core/css/CSSFontFace.h"
#include "core/css/CSSFontSelector.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFaceCreationParams.h"
#include "platform/fonts/SegmentedFontData.h"
#include "platform/fonts/SimpleFontData.h"
namespace blink {
CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* font_selector,
FontTraits traits)
: font_selector_(font_selector),
traits_(traits),
first_non_css_connected_face_(font_faces_.end()),
approximate_character_count_(0) {}
CSSSegmentedFontFace::~CSSSegmentedFontFace() {}
void CSSSegmentedFontFace::PruneTable() {
// Make sure the glyph page tree prunes out all uses of this custom font.
if (font_data_table_.IsEmpty())
return;
font_data_table_.clear();
}
bool CSSSegmentedFontFace::IsValid() const {
// Valid if at least one font face is valid.
for (const auto& font_face : font_faces_) {
if (font_face->CssFontFace()->IsValid())
return true;
}
return false;
}
void CSSSegmentedFontFace::FontFaceInvalidated() {
PruneTable();
}
void CSSSegmentedFontFace::AddFontFace(FontFace* font_face,
bool css_connected) {
PruneTable();
font_face->CssFontFace()->SetSegmentedFontFace(this);
if (css_connected) {
font_faces_.InsertBefore(first_non_css_connected_face_, font_face);
} else {
// This is the only place in Blink that is using addReturnIterator.
FontFaceList::iterator iterator = font_faces_.AddReturnIterator(font_face);
if (first_non_css_connected_face_ == font_faces_.end())
first_non_css_connected_face_ = iterator;
}
}
void CSSSegmentedFontFace::RemoveFontFace(FontFace* font_face) {
FontFaceList::iterator it = font_faces_.find(font_face);
if (it == font_faces_.end())
return;
if (it == first_non_css_connected_face_)
++first_non_css_connected_face_;
font_faces_.erase(it);
PruneTable();
font_face->CssFontFace()->ClearSegmentedFontFace();
}
PassRefPtr<FontData> CSSSegmentedFontFace::GetFontData(
const FontDescription& font_description) {
if (!IsValid())
return nullptr;
FontTraits desired_traits = font_description.Traits();
FontCacheKey key =
font_description.CacheKey(FontFaceCreationParams(), desired_traits);
RefPtr<SegmentedFontData>& font_data =
font_data_table_.insert(key, nullptr).stored_value->value;
if (font_data && font_data->NumFaces()) {
// No release, we have a reference to an object in the cache which should
// retain the ref count it has.
return font_data;
}
if (!font_data)
font_data = SegmentedFontData::Create();
FontDescription requested_font_description(font_description);
requested_font_description.SetTraits(traits_);
requested_font_description.SetSyntheticBold(
traits_.Weight() < kFontWeight600 &&
desired_traits.Weight() >= kFontWeight600);
requested_font_description.SetSyntheticItalic(
traits_.Style() == kFontStyleNormal &&
desired_traits.Style() == kFontStyleItalic);
for (FontFaceList::reverse_iterator it = font_faces_.rbegin();
it != font_faces_.rend(); ++it) {
if (!(*it)->CssFontFace()->IsValid())
continue;
if (RefPtr<SimpleFontData> face_font_data =
(*it)->CssFontFace()->GetFontData(requested_font_description)) {
DCHECK(!face_font_data->IsSegmented());
if (face_font_data->IsCustomFont()) {
font_data->AppendFace(AdoptRef(new FontDataForRangeSet(
std::move(face_font_data), (*it)->CssFontFace()->Ranges())));
} else {
font_data->AppendFace(AdoptRef(new FontDataForRangeSetFromCache(
std::move(face_font_data), (*it)->CssFontFace()->Ranges())));
}
}
}
if (font_data->NumFaces()) {
// No release, we have a reference to an object in the cache which should
// retain the ref count it has.
return font_data;
}
return nullptr;
}
void CSSSegmentedFontFace::WillUseFontData(
const FontDescription& font_description,
const String& text) {
approximate_character_count_ += text.length();
for (FontFaceList::reverse_iterator it = font_faces_.rbegin();
it != font_faces_.rend(); ++it) {
if ((*it)->LoadStatus() != FontFace::kUnloaded)
break;
if ((*it)->CssFontFace()->MaybeLoadFont(font_description, text))
break;
}
}
void CSSSegmentedFontFace::WillUseRange(
const blink::FontDescription& font_description,
const blink::FontDataForRangeSet& range_set) {
// Iterating backwards since later defined unicode-range faces override
// previously defined ones, according to the CSS3 fonts module.
// https://drafts.csswg.org/css-fonts/#composite-fonts
for (FontFaceList::reverse_iterator it = font_faces_.rbegin();
it != font_faces_.rend(); ++it) {
CSSFontFace* css_font_face = (*it)->CssFontFace();
if (css_font_face->MaybeLoadFont(font_description, range_set))
break;
}
}
bool CSSSegmentedFontFace::CheckFont(const String& text) const {
for (const auto& font_face : font_faces_) {
if (font_face->LoadStatus() != FontFace::kLoaded &&
font_face->CssFontFace()->Ranges()->IntersectsWith(text))
return false;
}
return true;
}
void CSSSegmentedFontFace::Match(const String& text,
HeapVector<Member<FontFace>>& faces) const {
for (const auto& font_face : font_faces_) {
if (font_face->CssFontFace()->Ranges()->IntersectsWith(text))
faces.push_back(font_face);
}
}
DEFINE_TRACE(CSSSegmentedFontFace) {
visitor->Trace(font_selector_);
visitor->Trace(first_non_css_connected_face_);
visitor->Trace(font_faces_);
}
} // namespace blink