blob: 212ae08ce3cb7059dfefd5f4d0f01b428544381a [file] [log] [blame]
/*
* Copyright (C) 2007 Apple Computer, Inc.
* Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved.
* Copyright (C) 2010 Company 100, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER 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/platform/fonts/font_custom_platform_data.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
#include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h"
#include "third_party/blink/renderer/platform/fonts/opentype/font_settings.h"
#include "third_party/blink/renderer/platform/fonts/opentype/variable_axes_names.h"
#include "third_party/blink/renderer/platform/fonts/web_font_decoder.h"
#include "third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace blink {
FontCustomPlatformData::FontCustomPlatformData(sk_sp<SkTypeface> typeface,
size_t data_size)
: base_typeface_(std::move(typeface)), data_size_(data_size) {}
FontCustomPlatformData::~FontCustomPlatformData() = default;
FontPlatformData FontCustomPlatformData::GetFontPlatformData(
float size,
bool bold,
bool italic,
const FontSelectionRequest& selection_request,
const FontSelectionCapabilities& selection_capabilities,
const OpticalSizing& optical_sizing,
FontOrientation orientation,
const FontVariationSettings* variation_settings) {
DCHECK(base_typeface_);
sk_sp<SkTypeface> return_typeface = base_typeface_;
// Maximum axis count is maximum value for the OpenType USHORT,
// which is a 16bit unsigned.
// https://www.microsoft.com/typography/otspec/fvar.htm Variation
// settings coming from CSS can have duplicate assignments and the
// list can be longer than UINT16_MAX, but ignoring the length for
// now, going with a reasonable upper limit. Deduplication is
// handled by Skia with priority given to the last occuring
// assignment.
FontFormatCheck::VariableFontSubType font_sub_type =
FontFormatCheck::ProbeVariableFont(base_typeface_);
if (font_sub_type ==
FontFormatCheck::VariableFontSubType::kVariableTrueType ||
font_sub_type == FontFormatCheck::VariableFontSubType::kVariableCFF2) {
Vector<SkFontArguments::VariationPosition::Coordinate, 0> variation;
SkFontArguments::VariationPosition::Coordinate weight_coordinate = {
SkSetFourByteTag('w', 'g', 'h', 't'),
SkFloatToScalar(selection_capabilities.weight.clampToRange(
selection_request.weight))};
SkFontArguments::VariationPosition::Coordinate width_coordinate = {
SkSetFourByteTag('w', 'd', 't', 'h'),
SkFloatToScalar(selection_capabilities.width.clampToRange(
selection_request.width))};
// CSS and OpenType have opposite definitions of direction of slant
// angle. In OpenType positive values turn counter-clockwise, negative
// values clockwise - in CSS positive values are clockwise rotations /
// skew. See note in https://drafts.csswg.org/css-fonts/#font-style-prop -
// map value from CSS to OpenType here.
SkFontArguments::VariationPosition::Coordinate slant_coordinate = {
SkSetFourByteTag('s', 'l', 'n', 't'),
SkFloatToScalar(-selection_capabilities.slope.clampToRange(
selection_request.slope))};
variation.push_back(weight_coordinate);
variation.push_back(width_coordinate);
variation.push_back(slant_coordinate);
bool explicit_opsz_configured = false;
if (variation_settings && variation_settings->size() < UINT16_MAX) {
variation.ReserveCapacity(variation_settings->size() + variation.size());
for (const auto& setting : *variation_settings) {
if (setting.Tag() == SkSetFourByteTag('o', 'p', 's', 'z'))
explicit_opsz_configured = true;
SkFontArguments::VariationPosition::Coordinate setting_coordinate =
{setting.Tag(), SkFloatToScalar(setting.Value())};
variation.push_back(setting_coordinate);
}
}
if (optical_sizing == kAutoOpticalSizing && !explicit_opsz_configured) {
SkFontArguments::VariationPosition::Coordinate opsz_coordinate =
{SkSetFourByteTag('o', 'p', 's', 'z'), SkFloatToScalar(size)};
variation.push_back(opsz_coordinate);
}
SkFontArguments font_args;
font_args.setVariationDesignPosition({variation.data(), variation.size()});
sk_sp<SkTypeface> sk_variation_font(base_typeface_->makeClone(font_args));
if (sk_variation_font) {
return_typeface = sk_variation_font;
} else {
SkString family_name;
base_typeface_->getFamilyName(&family_name);
// TODO: Surface this as a console message?
LOG(ERROR) << "Unable for apply variation axis properties for font: "
<< family_name.c_str();
}
}
return FontPlatformData(std::move(return_typeface), std::string(), size,
bold && !base_typeface_->isBold(),
italic && !base_typeface_->isItalic(), orientation);
}
Vector<VariationAxis> FontCustomPlatformData::GetVariationAxes() const {
return VariableAxesNames::GetVariationAxes(base_typeface_);
}
String FontCustomPlatformData::FamilyNameForInspector() const {
SkTypeface::LocalizedStrings* font_family_iterator =
base_typeface_->createFamilyNameIterator();
SkTypeface::LocalizedString localized_string;
while (font_family_iterator->next(&localized_string)) {
// BCP 47 tags for English take precedent in font matching over other
// localizations: https://drafts.csswg.org/css-fonts/#descdef-src.
if (localized_string.fLanguage.equals("en") ||
localized_string.fLanguage.equals("en-US")) {
break;
}
}
font_family_iterator->unref();
return String::FromUTF8(localized_string.fString.c_str(),
localized_string.fString.size());
}
scoped_refptr<FontCustomPlatformData> FontCustomPlatformData::Create(
SharedBuffer* buffer,
String& ots_parse_message) {
DCHECK(buffer);
WebFontDecoder decoder;
sk_sp<SkTypeface> typeface = decoder.Decode(buffer);
if (!typeface) {
ots_parse_message = decoder.GetErrorString();
return nullptr;
}
return base::AdoptRef(
new FontCustomPlatformData(std::move(typeface), decoder.DecodedSize()));
}
bool FontCustomPlatformData::SupportsFormat(const String& format) {
// Support relevant format specifiers from
// https://drafts.csswg.org/css-fonts-4/#src-desc
return EqualIgnoringASCIICase(format, "woff") ||
EqualIgnoringASCIICase(format, "truetype") ||
EqualIgnoringASCIICase(format, "opentype") ||
EqualIgnoringASCIICase(format, "woff2") ||
EqualIgnoringASCIICase(format, "woff-variations") ||
EqualIgnoringASCIICase(format, "truetype-variations") ||
EqualIgnoringASCIICase(format, "opentype-variations") ||
EqualIgnoringASCIICase(format, "woff2-variations");
}
bool FontCustomPlatformData::MayBeIconFont() const {
if (!may_be_icon_font_computed_) {
// We observed that many icon fonts define almost all of their glyphs in the
// Unicode Private Use Area, while non-icon fonts rarely use PUA. We use
// this as a heuristic to determine if a font is an icon font.
// We first obtain the list of glyphs mapped from PUA codepoint range:
// https://unicode.org/charts/PDF/UE000.pdf
// Note: The two supplementary PUA here are too long but not used much by
// icon fonts, so we don't include them in this heuristic.
wtf_size_t pua_length =
kPrivateUseLastCharacter - kPrivateUseFirstCharacter + 1;
Vector<SkUnichar> pua_codepoints(pua_length);
for (wtf_size_t i = 0; i < pua_length; ++i)
pua_codepoints[i] = kPrivateUseFirstCharacter + i;
Vector<SkGlyphID> glyphs(pua_codepoints.size());
base_typeface_->unicharsToGlyphs(pua_codepoints.data(),
pua_codepoints.size(), glyphs.data());
// Deduplicate and exclude glyph ID 0 (which means undefined glyph)
std::sort(glyphs.begin(), glyphs.end());
glyphs.erase(std::unique(glyphs.begin(), glyphs.end()), glyphs.end());
if (!glyphs[0])
glyphs.EraseAt(0);
// We use the heuristic that if more than half of the define glyphs are in
// PUA, then the font may be an icon font.
wtf_size_t pua_glyph_count = glyphs.size();
wtf_size_t total_glyphs = base_typeface_->countGlyphs();
may_be_icon_font_ = pua_glyph_count * 2 > total_glyphs;
}
return may_be_icon_font_;
}
} // namespace blink