blob: b8c4da4b2f2a63b16a2ba2547c7adfcb0bc34709 [file] [log] [blame]
/*
* Copyright (C) 2007 Nicholas Shanks <contact@nickshanks.com>
* 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.
* 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 "platform/fonts/FontDescription.h"
#include "platform/Language.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "wtf/StringHasher.h"
#include "wtf/text/AtomicStringHash.h"
#include "wtf/text/StringHash.h"
namespace blink {
struct SameSizeAsFontDescription {
DISALLOW_NEW();
FontFamily familyList;
RefPtr<FontFeatureSettings> m_featureSettings;
RefPtr<FontVariationSettings> m_variationSettings;
AtomicString locale;
float sizes[6];
FieldsAsUnsignedType bitfields;
};
static_assert(sizeof(FontDescription) == sizeof(SameSizeAsFontDescription),
"FontDescription should stay small");
TypesettingFeatures FontDescription::s_defaultTypesettingFeatures = 0;
bool FontDescription::s_useSubpixelTextPositioning = false;
FontDescription::FontDescription()
: m_specifiedSize(0),
m_computedSize(0),
m_adjustedSize(0),
m_sizeAdjust(FontSizeAdjustNone),
m_letterSpacing(0),
m_wordSpacing(0) {
m_fieldsAsUnsigned.parts[0] = 0;
m_fieldsAsUnsigned.parts[1] = 0;
m_fields.m_orientation = static_cast<unsigned>(FontOrientation::Horizontal);
m_fields.m_widthVariant = RegularWidth;
m_fields.m_style = FontStyleNormal;
m_fields.m_variantCaps = CapsNormal;
m_fields.m_isAbsoluteSize = false;
m_fields.m_weight = FontWeightNormal;
m_fields.m_stretch = FontStretchNormal;
m_fields.m_genericFamily = NoFamily;
m_fields.m_kerning = AutoKerning;
m_fields.m_commonLigaturesState = NormalLigaturesState;
m_fields.m_discretionaryLigaturesState = NormalLigaturesState;
m_fields.m_historicalLigaturesState = NormalLigaturesState;
m_fields.m_contextualLigaturesState = NormalLigaturesState;
m_fields.m_keywordSize = 0;
m_fields.m_fontSmoothing = AutoSmoothing;
m_fields.m_textRendering = AutoTextRendering;
m_fields.m_syntheticBold = false;
m_fields.m_syntheticItalic = false;
m_fields.m_subpixelTextPosition = s_useSubpixelTextPositioning;
m_fields.m_typesettingFeatures = s_defaultTypesettingFeatures;
m_fields.m_variantNumeric = FontVariantNumeric().m_fieldsAsUnsigned;
m_fields.m_subpixelAscentDescent = false;
}
FontDescription::FontDescription(const FontDescription&) = default;
FontDescription& FontDescription::operator=(const FontDescription&) = default;
bool FontDescription::operator==(const FontDescription& other) const {
return m_familyList == other.m_familyList && m_locale == other.m_locale &&
m_specifiedSize == other.m_specifiedSize &&
m_computedSize == other.m_computedSize &&
m_adjustedSize == other.m_adjustedSize &&
m_sizeAdjust == other.m_sizeAdjust &&
m_letterSpacing == other.m_letterSpacing &&
m_wordSpacing == other.m_wordSpacing &&
m_fieldsAsUnsigned.parts[0] == other.m_fieldsAsUnsigned.parts[0] &&
m_fieldsAsUnsigned.parts[1] == other.m_fieldsAsUnsigned.parts[1] &&
(m_featureSettings == other.m_featureSettings ||
(m_featureSettings && other.m_featureSettings &&
*m_featureSettings == *other.m_featureSettings)) &&
(m_variationSettings == other.m_variationSettings ||
(m_variationSettings && other.m_variationSettings &&
*m_variationSettings == *other.m_variationSettings));
}
FontWeight FontDescription::lighterWeight(FontWeight weight) {
switch (weight) {
case FontWeight100:
case FontWeight200:
case FontWeight300:
case FontWeight400:
case FontWeight500:
return FontWeight100;
case FontWeight600:
case FontWeight700:
return FontWeight400;
case FontWeight800:
case FontWeight900:
return FontWeight700;
}
ASSERT_NOT_REACHED();
return FontWeightNormal;
}
FontWeight FontDescription::bolderWeight(FontWeight weight) {
switch (weight) {
case FontWeight100:
case FontWeight200:
case FontWeight300:
return FontWeight400;
case FontWeight400:
case FontWeight500:
return FontWeight700;
case FontWeight600:
case FontWeight700:
case FontWeight800:
case FontWeight900:
return FontWeight900;
}
ASSERT_NOT_REACHED();
return FontWeightNormal;
}
FontDescription::Size FontDescription::largerSize(const Size& size) {
return Size(0, size.value * 1.2, size.isAbsolute);
}
FontDescription::Size FontDescription::smallerSize(const Size& size) {
return Size(0, size.value / 1.2, size.isAbsolute);
}
FontTraits FontDescription::traits() const {
return FontTraits(style(), weight(), stretch());
}
FontDescription::VariantLigatures FontDescription::getVariantLigatures() const {
VariantLigatures ligatures;
ligatures.common = commonLigaturesState();
ligatures.discretionary = discretionaryLigaturesState();
ligatures.historical = historicalLigaturesState();
ligatures.contextual = contextualLigaturesState();
return ligatures;
}
void FontDescription::setTraits(FontTraits traits) {
setStyle(traits.style());
setWeight(traits.weight());
setStretch(traits.stretch());
}
void FontDescription::setVariantCaps(FontVariantCaps variantCaps) {
m_fields.m_variantCaps = variantCaps;
updateTypesettingFeatures();
}
void FontDescription::setVariantLigatures(const VariantLigatures& ligatures) {
m_fields.m_commonLigaturesState = ligatures.common;
m_fields.m_discretionaryLigaturesState = ligatures.discretionary;
m_fields.m_historicalLigaturesState = ligatures.historical;
m_fields.m_contextualLigaturesState = ligatures.contextual;
updateTypesettingFeatures();
}
void FontDescription::setVariantNumeric(
const FontVariantNumeric& variantNumeric) {
m_fields.m_variantNumeric = variantNumeric.m_fieldsAsUnsigned;
updateTypesettingFeatures();
}
float FontDescription::effectiveFontSize() const {
// Ensure that the effective precision matches the font-cache precision.
// This guarantees that the same precision is used regardless of cache status.
float computedOrAdjustedSize =
hasSizeAdjust() ? adjustedSize() : computedSize();
return floorf(computedOrAdjustedSize * FontCacheKey::precisionMultiplier()) /
FontCacheKey::precisionMultiplier();
}
FontCacheKey FontDescription::cacheKey(
const FontFaceCreationParams& creationParams,
FontTraits desiredTraits) const {
FontTraits fontTraits = desiredTraits.bitfield() ? desiredTraits : traits();
unsigned options =
static_cast<unsigned>(m_fields.m_syntheticItalic) << 6 | // bit 7
static_cast<unsigned>(m_fields.m_syntheticBold) << 5 | // bit 6
static_cast<unsigned>(m_fields.m_textRendering) << 3 | // bits 4-5
static_cast<unsigned>(m_fields.m_orientation) << 1 | // bit 2-3
static_cast<unsigned>(m_fields.m_subpixelTextPosition); // bit 1
return FontCacheKey(creationParams, effectiveFontSize(),
options | fontTraits.bitfield() << 8,
m_variationSettings);
}
void FontDescription::setDefaultTypesettingFeatures(
TypesettingFeatures typesettingFeatures) {
s_defaultTypesettingFeatures = typesettingFeatures;
}
TypesettingFeatures FontDescription::defaultTypesettingFeatures() {
return s_defaultTypesettingFeatures;
}
void FontDescription::updateTypesettingFeatures() {
m_fields.m_typesettingFeatures = s_defaultTypesettingFeatures;
switch (textRendering()) {
case AutoTextRendering:
break;
case OptimizeSpeed:
m_fields.m_typesettingFeatures &= ~(blink::Kerning | Ligatures);
break;
case GeometricPrecision:
case OptimizeLegibility:
m_fields.m_typesettingFeatures |= blink::Kerning | Ligatures;
break;
}
switch (getKerning()) {
case FontDescription::NoneKerning:
m_fields.m_typesettingFeatures &= ~blink::Kerning;
break;
case FontDescription::NormalKerning:
m_fields.m_typesettingFeatures |= blink::Kerning;
break;
case FontDescription::AutoKerning:
break;
}
// As per CSS (http://dev.w3.org/csswg/css-text-3/#letter-spacing-property),
// When the effective letter-spacing between two characters is not zero (due
// to either justification or non-zero computed letter-spacing), user agents
// should not apply optional ligatures.
if (m_letterSpacing == 0) {
switch (commonLigaturesState()) {
case FontDescription::DisabledLigaturesState:
m_fields.m_typesettingFeatures &= ~blink::Ligatures;
break;
case FontDescription::EnabledLigaturesState:
m_fields.m_typesettingFeatures |= blink::Ligatures;
break;
case FontDescription::NormalLigaturesState:
break;
}
if (discretionaryLigaturesState() ==
FontDescription::EnabledLigaturesState ||
historicalLigaturesState() == FontDescription::EnabledLigaturesState ||
contextualLigaturesState() == FontDescription::EnabledLigaturesState) {
m_fields.m_typesettingFeatures |= blink::Ligatures;
}
}
if (variantCaps() != CapsNormal)
m_fields.m_typesettingFeatures |= blink::Caps;
}
static inline void addToHash(unsigned& hash, unsigned key) {
hash = ((hash << 5) + hash) + key; // Djb2
}
static inline void addFloatToHash(unsigned& hash, float value) {
addToHash(hash, StringHasher::hashMemory(&value, sizeof(value)));
}
unsigned FontDescription::styleHashWithoutFamilyList() const {
unsigned hash = 0;
StringHasher stringHasher;
const FontFeatureSettings* settings = featureSettings();
if (settings) {
unsigned numFeatures = settings->size();
for (unsigned i = 0; i < numFeatures; ++i) {
const AtomicString& tag = settings->at(i).tag();
for (unsigned j = 0; j < tag.length(); j++)
stringHasher.addCharacter(tag[j]);
addToHash(hash, settings->at(i).value());
}
}
if (variationSettings())
addToHash(hash, variationSettings()->hash());
if (m_locale) {
const AtomicString& locale = m_locale->localeString();
for (unsigned i = 0; i < locale.length(); i++)
stringHasher.addCharacter(locale[i]);
}
addToHash(hash, stringHasher.hash());
addFloatToHash(hash, m_specifiedSize);
addFloatToHash(hash, m_computedSize);
addFloatToHash(hash, m_adjustedSize);
addFloatToHash(hash, m_sizeAdjust);
addFloatToHash(hash, m_letterSpacing);
addFloatToHash(hash, m_wordSpacing);
addToHash(hash, m_fieldsAsUnsigned.parts[0]);
addToHash(hash, m_fieldsAsUnsigned.parts[1]);
return hash;
}
SkFontStyle FontDescription::skiaFontStyle() const {
int width = static_cast<int>(stretch());
SkFontStyle::Slant slant = SkFontStyle::kUpright_Slant;
switch (style()) {
case FontStyleNormal:
slant = SkFontStyle::kUpright_Slant;
break;
case FontStyleItalic:
slant = SkFontStyle::kItalic_Slant;
break;
case FontStyleOblique:
slant = SkFontStyle::kOblique_Slant;
break;
default:
NOTREACHED();
break;
}
return SkFontStyle(numericFontWeight(weight()), width, slant);
static_assert(
static_cast<int>(FontStretchUltraCondensed) ==
static_cast<int>(SkFontStyle::kUltraCondensed_Width),
"FontStretchUltraCondensed should map to kUltraCondensed_Width");
static_assert(static_cast<int>(FontStretchNormal) ==
static_cast<int>(SkFontStyle::kNormal_Width),
"FontStretchNormal should map to kNormal_Width");
static_assert(static_cast<int>(FontStretchUltraExpanded) ==
static_cast<int>(SkFontStyle::kUltraExpanded_Width),
"FontStretchUltraExpanded should map to kUltraExpanded_Width");
}
} // namespace blink