blob: 40aaf9dbccb7ffef34f514f10bc0bef54c16d1ce [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style_ license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/layout/text_decoration_offset_base.h"
#include <algorithm>
#include <base/optional.h>
#include "third_party/blink/renderer/core/paint/text_decoration_info.h"
#include "third_party/blink/renderer/platform/fonts/font_metrics.h"
#include "third_party/blink/renderer/platform/fonts/font_vertical_position_type.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace {
int ComputeUnderlineOffsetAuto(const blink::FontMetrics& font_metrics,
float text_underline_offset,
float text_decoration_thickness) {
// Compute the gap between the font and the underline. Use at least one
// pixel gap, if underline is thick then use a bigger gap.
// Underline position of zero means draw underline on Baseline Position,
// in Blink we need at least 1-pixel gap to adding following check.
// Positive underline Position means underline should be drawn above baseline
// and negative value means drawing below baseline, negating the value as in
// Blink downward Y-increases.
int gap = std::max<int>(1, ceilf(text_decoration_thickness / 2.f));
// Position underline near the alphabetic baseline.
return font_metrics.Ascent() + gap + roundf(text_underline_offset);
}
base::Optional<int> ComputeUnderlineOffsetFromFont(
const blink::FontMetrics& font_metrics,
float text_underline_offset) {
if (!font_metrics.UnderlinePosition())
return base::nullopt;
return roundf(font_metrics.FloatAscent() + *font_metrics.UnderlinePosition() +
text_underline_offset);
}
} // namespace
namespace blink {
int TextDecorationOffsetBase::ComputeUnderlineOffset(
ResolvedUnderlinePosition underline_position,
float computed_font_size,
const FontMetrics& font_metrics,
const Length& style_underline_offset,
float text_decoration_thickness) const {
float style_underline_offset_pixels =
StyleUnderlineOffsetToPixels(style_underline_offset, computed_font_size);
switch (underline_position) {
default:
NOTREACHED();
FALLTHROUGH;
case ResolvedUnderlinePosition::kNearAlphabeticBaselineFromFont:
DCHECK(RuntimeEnabledFeatures::UnderlineOffsetThicknessEnabled());
return ComputeUnderlineOffsetFromFont(font_metrics,
style_underline_offset_pixels)
.value_or(ComputeUnderlineOffsetAuto(font_metrics,
style_underline_offset_pixels,
text_decoration_thickness));
case ResolvedUnderlinePosition::kNearAlphabeticBaselineAuto:
return ComputeUnderlineOffsetAuto(font_metrics,
style_underline_offset_pixels,
text_decoration_thickness);
case ResolvedUnderlinePosition::kUnder:
// Position underline at the under edge of the lowest element's
// content box.
return ComputeUnderlineOffsetForUnder(
style_underline_offset, computed_font_size, text_decoration_thickness,
FontVerticalPositionType::BottomOfEmHeight);
}
}
/* static */
float TextDecorationOffsetBase::StyleUnderlineOffsetToPixels(
const Length& style_underline_offset,
float font_size) {
if (style_underline_offset.IsAuto())
return 0;
return FloatValueForLength(style_underline_offset, font_size);
}
} // namespace blink