blob: 17da23f3a8dfa373c4ffa74c266220a4a90b7f44 [file]
/*
* 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.
*/
#include "platform/fonts/FontSelectionAlgorithm.h"
namespace blink {
auto FontSelectionAlgorithm::StretchDistance(
FontSelectionCapabilities capabilities) const -> DistanceResult {
auto width = capabilities.width;
DCHECK(width.IsValid());
if (width.Includes(request_.width))
return {FontSelectionValue(), request_.width};
if (request_.width > NormalWidthValue()) {
if (width.minimum > request_.width)
return {width.minimum - request_.width, width.minimum};
DCHECK(width.maximum < request_.width);
auto threshold =
std::max(request_.width, capabilities_bounds_.width.maximum);
return {threshold - width.maximum, width.maximum};
}
if (width.maximum < request_.width)
return {request_.width - width.maximum, width.maximum};
DCHECK(width.minimum > request_.width);
auto threshold = std::min(request_.width, capabilities_bounds_.width.minimum);
return {width.minimum - threshold, width.minimum};
}
auto FontSelectionAlgorithm::StyleDistance(
FontSelectionCapabilities capabilities) const -> DistanceResult {
auto slope = capabilities.slope;
DCHECK(slope.IsValid());
if (slope.Includes(request_.slope))
return {FontSelectionValue(), request_.slope};
if (request_.slope >= ItalicThreshold()) {
if (slope.minimum > request_.slope)
return {slope.minimum - request_.slope, slope.minimum};
DCHECK(request_.slope > slope.maximum);
auto threshold =
std::max(request_.slope, capabilities_bounds_.slope.maximum);
return {threshold - slope.maximum, slope.maximum};
}
if (request_.slope >= FontSelectionValue()) {
if (slope.maximum >= FontSelectionValue() && slope.maximum < request_.slope)
return {request_.slope - slope.maximum, slope.maximum};
if (slope.minimum > request_.slope)
return {slope.minimum, slope.minimum};
DCHECK(slope.maximum < FontSelectionValue());
auto threshold =
std::max(request_.slope, capabilities_bounds_.slope.maximum);
return {threshold - slope.maximum, slope.maximum};
}
if (request_.slope > -ItalicThreshold()) {
if (slope.minimum > request_.slope && slope.minimum <= FontSelectionValue())
return {slope.minimum - request_.slope, slope.minimum};
if (slope.maximum < request_.slope)
return {-slope.maximum, slope.maximum};
DCHECK(slope.minimum > FontSelectionValue());
auto threshold =
std::min(request_.slope, capabilities_bounds_.slope.minimum);
return {slope.minimum - threshold, slope.minimum};
}
if (slope.maximum < request_.slope)
return {request_.slope - slope.maximum, slope.maximum};
DCHECK(slope.minimum > request_.slope);
auto threshold = std::min(request_.slope, capabilities_bounds_.slope.minimum);
return {slope.minimum - threshold, slope.minimum};
}
auto FontSelectionAlgorithm::WeightDistance(
FontSelectionCapabilities capabilities) const -> DistanceResult {
auto weight = capabilities.weight;
DCHECK(weight.IsValid());
if (weight.Includes(request_.weight))
return {FontSelectionValue(), request_.weight};
// The spec states, for weights 400 and 500: "If the desired weight is
// 400, 500 is checked first ... If the desired weight is 500, 400 is
// checked first", section 4.c) of
// https://drafts.csswg.org/css-fonts/#font-style-matching section
FontSelectionValue offset(1);
if (request_.weight == FontSelectionValue(400) &&
weight.Includes(FontSelectionValue(500)))
return {offset, FontSelectionValue(500)};
if (request_.weight == FontSelectionValue(500) &&
weight.Includes(FontSelectionValue(400)))
return {offset, FontSelectionValue(400)};
if (request_.weight <= WeightSearchThreshold()) {
if (weight.maximum < request_.weight)
return {request_.weight - weight.maximum + offset, weight.maximum};
DCHECK(weight.minimum > request_.weight);
auto threshold =
std::min(request_.weight, capabilities_bounds_.weight.minimum);
return {weight.minimum - threshold + offset, weight.minimum};
}
if (weight.minimum > request_.weight)
return {weight.minimum - request_.weight + offset, weight.minimum};
DCHECK(weight.maximum < request_.weight);
auto threshold =
std::max(request_.weight, capabilities_bounds_.weight.maximum);
return {threshold - weight.maximum + offset, weight.maximum};
}
bool FontSelectionAlgorithm::IsBetterMatchForRequest(
const FontSelectionCapabilities& firstCapabilities,
const FontSelectionCapabilities& secondCapabilities) {
auto stretchDistanceFirst = StretchDistance(firstCapabilities).distance;
auto stretchDistanceSecond = StretchDistance(secondCapabilities).distance;
if (stretchDistanceFirst < stretchDistanceSecond)
return true;
if (stretchDistanceFirst > stretchDistanceSecond)
return false;
auto styleDistanceFirst = StyleDistance(firstCapabilities).distance;
auto styleDistanceSecond = StyleDistance(secondCapabilities).distance;
if (styleDistanceFirst < styleDistanceSecond)
return true;
if (styleDistanceFirst > styleDistanceSecond)
return false;
auto weightDistanceFirst = WeightDistance(firstCapabilities).distance;
auto weightDistanceSecond = WeightDistance(secondCapabilities).distance;
if (weightDistanceFirst < weightDistanceSecond)
return true;
return false;
}
} // namespace blink