blob: 06d293f01a68dc2029fb147bd566fec4d84bf117 [file] [log] [blame]
/*
* Copyright (C) 2017 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 INC. 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 INC. 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.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_SELECTION_TYPES_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_SELECTION_TYPES_H_
#include "base/numerics/ranges.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
// Unclamped, unchecked, signed fixed-point number representing a value used for
// font variations. Sixteen bits in total, one sign bit, two fractional bits,
// means the smallest positive representable value is 0.25, the maximum
// representable value is 8191.75, and the minimum representable value is -8192.
class PLATFORM_EXPORT FontSelectionValue {
USING_FAST_MALLOC(FontSelectionValue);
public:
FontSelectionValue() = default;
// Explicit because it is lossy.
explicit FontSelectionValue(int x)
: backing_(clampTo<int16_t>(x * fractionalEntropy)) {}
// Explicit because it is lossy.
explicit FontSelectionValue(float x)
: backing_(clampTo<int16_t>(x * fractionalEntropy)) {}
// Explicit because it is lossy.
explicit FontSelectionValue(double x)
: backing_(clampTo<int16_t>(x * fractionalEntropy)) {}
operator float() const {
// floats have 23 fractional bits, but only 14 fractional bits are
// necessary, so every value can be represented losslessly.
return backing_ / static_cast<float>(fractionalEntropy);
}
FontSelectionValue operator+(const FontSelectionValue other) const;
FontSelectionValue operator-(const FontSelectionValue other) const;
FontSelectionValue operator*(const FontSelectionValue other) const;
FontSelectionValue operator/(const FontSelectionValue other) const;
FontSelectionValue operator-() const;
bool operator==(const FontSelectionValue other) const;
bool operator!=(const FontSelectionValue other) const;
bool operator<(const FontSelectionValue other) const;
bool operator<=(const FontSelectionValue other) const;
bool operator>(const FontSelectionValue other) const;
bool operator>=(const FontSelectionValue other) const;
int16_t RawValue() const { return backing_; }
String ToString() const;
static const FontSelectionValue& MaximumValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
const FontSelectionValue, maximumValue,
(std::numeric_limits<int16_t>::max(), RawTag::RawTag));
return maximumValue;
}
static const FontSelectionValue& MinimumValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
const FontSelectionValue, minimumValue,
(std::numeric_limits<int16_t>::min(), RawTag::RawTag));
return minimumValue;
}
protected:
enum class RawTag { RawTag };
FontSelectionValue(int16_t rawValue, RawTag) : backing_(rawValue) {}
private:
static constexpr int fractionalEntropy = 4;
// TODO(drott) crbug.com/745910 - Consider making this backed by a checked
// arithmetic type.
int16_t backing_{0};
};
inline FontSelectionValue FontSelectionValue::operator+(
const FontSelectionValue other) const {
return FontSelectionValue(backing_ + other.backing_, RawTag::RawTag);
}
inline FontSelectionValue FontSelectionValue::operator-(
const FontSelectionValue other) const {
return FontSelectionValue(backing_ - other.backing_, RawTag::RawTag);
}
inline FontSelectionValue FontSelectionValue::operator*(
const FontSelectionValue other) const {
return FontSelectionValue(
static_cast<int32_t>(backing_) * other.backing_ / fractionalEntropy,
RawTag::RawTag);
}
inline FontSelectionValue FontSelectionValue::operator/(
const FontSelectionValue other) const {
return FontSelectionValue(
static_cast<int32_t>(backing_) / other.backing_ * fractionalEntropy,
RawTag::RawTag);
}
inline FontSelectionValue FontSelectionValue::operator-() const {
return FontSelectionValue(-backing_, RawTag::RawTag);
}
inline bool FontSelectionValue::operator==(
const FontSelectionValue other) const {
return backing_ == other.backing_;
}
inline bool FontSelectionValue::operator!=(
const FontSelectionValue other) const {
return !operator==(other);
}
inline bool FontSelectionValue::operator<(
const FontSelectionValue other) const {
return backing_ < other.backing_;
}
inline bool FontSelectionValue::operator<=(
const FontSelectionValue other) const {
return backing_ <= other.backing_;
}
inline bool FontSelectionValue::operator>(
const FontSelectionValue other) const {
return backing_ > other.backing_;
}
inline bool FontSelectionValue::operator>=(
const FontSelectionValue other) const {
return backing_ >= other.backing_;
}
static inline const FontSelectionValue& ItalicThreshold() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, italicThreshold,
(20));
return italicThreshold;
}
static inline bool isItalic(FontSelectionValue fontWeight) {
return fontWeight >= ItalicThreshold();
}
static inline const FontSelectionValue& FontSelectionZeroValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
fontSelectionZeroValue, (0));
return fontSelectionZeroValue;
}
static inline const FontSelectionValue& NormalSlopeValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, normalSlopeValue,
());
return normalSlopeValue;
}
static inline const FontSelectionValue& ItalicSlopeValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, italicValue, (20));
return italicValue;
}
static inline const FontSelectionValue& MaxObliqueValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, maxObliqueValue,
(90));
return maxObliqueValue;
}
static inline const FontSelectionValue& MinObliqueValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, minObliqueValue,
(-90));
return minObliqueValue;
}
static inline const FontSelectionValue& BoldThreshold() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, boldThreshold,
(600));
return boldThreshold;
}
static inline const FontSelectionValue& MinWeightValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, minWeightValue,
(1));
return minWeightValue;
}
static inline const FontSelectionValue& MaxWeightValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, maxWeightValue,
(1000));
return maxWeightValue;
}
static inline const FontSelectionValue& BoldWeightValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, boldWeightValue,
(700));
return boldWeightValue;
}
static inline const FontSelectionValue& NormalWeightValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, normalWeightValue,
(400));
return normalWeightValue;
}
static inline const FontSelectionValue& LightWeightValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, lightWeightValue,
(200));
return lightWeightValue;
}
static inline bool isFontWeightBold(FontSelectionValue fontWeight) {
return fontWeight >= BoldThreshold();
}
static inline const FontSelectionValue& UpperWeightSearchThreshold() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
upperWeightSearchThreshold, (500));
return upperWeightSearchThreshold;
}
static inline const FontSelectionValue& LowerWeightSearchThreshold() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
lowerWeightSearchThreshold, (400));
return lowerWeightSearchThreshold;
}
static inline const FontSelectionValue& UltraCondensedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
ultraCondensedWidthValue, (50));
return ultraCondensedWidthValue;
}
static inline const FontSelectionValue& ExtraCondensedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
extraCondensedWidthValue, (62.5f));
return extraCondensedWidthValue;
}
static inline const FontSelectionValue& CondensedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, condensedWidthValue,
(75));
return condensedWidthValue;
}
static inline const FontSelectionValue& SemiCondensedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
semiCondensedWidthValue, (87.5f));
return semiCondensedWidthValue;
}
static inline const FontSelectionValue& NormalWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, normalWidthValue,
(100.0f));
return normalWidthValue;
}
static inline const FontSelectionValue& SemiExpandedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
semiExpandedWidthValue, (112.5f));
return semiExpandedWidthValue;
}
static inline const FontSelectionValue& ExpandedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue, expandedWidthValue,
(125));
return expandedWidthValue;
}
static inline const FontSelectionValue& ExtraExpandedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
extraExpandedWidthValue, (150));
return extraExpandedWidthValue;
}
static inline const FontSelectionValue& UltraExpandedWidthValue() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontSelectionValue,
ultraExpandedWidthValue, (200));
return ultraExpandedWidthValue;
}
struct FontSelectionRange {
FontSelectionRange(FontSelectionValue single_value)
: minimum(single_value), maximum(single_value) {}
FontSelectionRange(FontSelectionValue minimum, FontSelectionValue maximum)
: minimum(minimum), maximum(maximum) {}
bool operator==(const FontSelectionRange& other) const {
return minimum == other.minimum && maximum == other.maximum;
}
bool IsValid() const { return minimum <= maximum; }
bool IsRange() const { return maximum > minimum; }
void Expand(const FontSelectionRange& other) {
DCHECK(other.IsValid());
if (!IsValid()) {
*this = other;
} else {
minimum = std::min(minimum, other.minimum);
maximum = std::max(maximum, other.maximum);
}
DCHECK(IsValid());
}
bool Includes(FontSelectionValue target) const {
return target >= minimum && target <= maximum;
}
uint32_t UniqueValue() const {
return minimum.RawValue() << 16 | maximum.RawValue();
}
FontSelectionValue clampToRange(FontSelectionValue selection_value) const {
return base::ClampToRange(selection_value, minimum, maximum);
}
FontSelectionValue minimum{FontSelectionValue(1)};
FontSelectionValue maximum{FontSelectionValue(0)};
};
struct PLATFORM_EXPORT FontSelectionRequest {
FontSelectionRequest() = default;
FontSelectionRequest(FontSelectionValue weight,
FontSelectionValue width,
FontSelectionValue slope)
: weight(weight), width(width), slope(slope) {}
unsigned GetHash() const;
bool operator==(const FontSelectionRequest& other) const {
return weight == other.weight && width == other.width &&
slope == other.slope;
}
bool operator!=(const FontSelectionRequest& other) const {
return !operator==(other);
}
String ToString() const;
FontSelectionValue weight;
FontSelectionValue width;
FontSelectionValue slope;
};
// Only used for HashMaps. We don't want to put the bool into
// FontSelectionRequest because FontSelectionRequest needs to be as small as
// possible because it's inside every FontDescription.
struct FontSelectionRequestKey {
FontSelectionRequestKey() = default;
FontSelectionRequestKey(FontSelectionRequest request) : request(request) {}
explicit FontSelectionRequestKey(WTF::HashTableDeletedValueType)
: isDeletedValue(true) {}
bool IsHashTableDeletedValue() const { return isDeletedValue; }
bool operator==(const FontSelectionRequestKey& other) const {
return request == other.request && isDeletedValue == other.isDeletedValue;
}
FontSelectionRequest request;
bool isDeletedValue{false};
};
struct PLATFORM_EXPORT FontSelectionRequestKeyHash {
static unsigned GetHash(const FontSelectionRequestKey&);
static bool Equal(const FontSelectionRequestKey& a,
const FontSelectionRequestKey& b) {
return a == b;
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
struct FontSelectionCapabilities {
FontSelectionCapabilities() = default;
FontSelectionCapabilities(FontSelectionRange width,
FontSelectionRange slope,
FontSelectionRange weight)
: width(width), slope(slope), weight(weight), is_deleted_value_(false) {}
FontSelectionCapabilities(WTF::HashTableDeletedValueType)
: is_deleted_value_(true) {}
bool IsHashTableDeletedValue() const { return is_deleted_value_; }
void Expand(const FontSelectionCapabilities& capabilities) {
width.Expand(capabilities.width);
slope.Expand(capabilities.slope);
weight.Expand(capabilities.weight);
}
bool IsValid() const {
return width.IsValid() && slope.IsValid() && weight.IsValid() &&
!is_deleted_value_;
}
bool HasRange() const {
return width.IsRange() || slope.IsRange() || weight.IsRange();
}
bool operator==(const FontSelectionCapabilities& other) const {
return width == other.width && slope == other.slope &&
weight == other.weight &&
is_deleted_value_ == other.is_deleted_value_;
}
bool operator!=(const FontSelectionCapabilities& other) const {
return !(*this == other);
}
FontSelectionRange width{FontSelectionZeroValue(), FontSelectionZeroValue()};
FontSelectionRange slope{FontSelectionZeroValue(), FontSelectionZeroValue()};
FontSelectionRange weight{FontSelectionZeroValue(), FontSelectionZeroValue()};
bool is_deleted_value_{false};
};
struct PLATFORM_EXPORT FontSelectionCapabilitiesHash {
static unsigned GetHash(const FontSelectionCapabilities& key);
static bool Equal(const FontSelectionCapabilities& a,
const FontSelectionCapabilities& b) {
return a == b;
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
} // namespace blink
namespace WTF {
template <>
struct DefaultHash<blink::FontSelectionCapabilities> {
STATIC_ONLY(DefaultHash);
typedef blink::FontSelectionCapabilitiesHash Hash;
};
template <>
struct HashTraits<blink::FontSelectionCapabilities>
: SimpleClassHashTraits<blink::FontSelectionCapabilities> {
STATIC_ONLY(HashTraits);
};
} // namespace WTF
// Used for clampTo for example in StyleBuilderConverter
template <>
inline blink::FontSelectionValue
defaultMinimumForClamp<blink::FontSelectionValue>() {
return blink::FontSelectionValue::MinimumValue();
}
template <>
inline blink::FontSelectionValue
defaultMaximumForClamp<blink::FontSelectionValue>() {
return blink::FontSelectionValue::MaximumValue();
}
#endif