blob: 7936129e4a18a994590028055654688833044d21 [file] [log] [blame]
// Copyright 2017 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/html/canvas/text_metrics.h"
#include "third_party/blink/renderer/core/html/canvas/baselines.h"
#include "third_party/blink/renderer/platform/fonts/character_range.h"
namespace blink {
constexpr int kHangingAsPercentOfAscent = 80;
float TextMetrics::GetFontBaseline(const TextBaseline& text_baseline,
const SimpleFontData& font_data) {
FontMetrics font_metrics = font_data.GetFontMetrics();
switch (text_baseline) {
case kTopTextBaseline:
return font_data.EmHeightAscent().ToFloat();
case kHangingTextBaseline:
// According to
// http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
// "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of
// the ascender height"
return font_metrics.FloatAscent() * kHangingAsPercentOfAscent / 100.0;
case kIdeographicTextBaseline:
return -font_metrics.FloatDescent();
case kBottomTextBaseline:
return -font_data.EmHeightDescent().ToFloat();
case kMiddleTextBaseline:
return (font_data.EmHeightAscent().ToFloat() -
font_data.EmHeightDescent().ToFloat()) /
2.0f;
case kAlphabeticTextBaseline:
default:
// Do nothing.
break;
}
return 0;
}
void TextMetrics::Trace(blink::Visitor* visitor) {
visitor->Trace(baselines_);
ScriptWrappable::Trace(visitor);
}
TextMetrics::TextMetrics() : baselines_(Baselines::Create()) {}
void TextMetrics::Update(const Font& font,
const TextDirection& direction,
const TextBaseline& baseline,
const TextAlign& align,
const String& text) {
const SimpleFontData* font_data = font.PrimaryFont();
if (!font_data)
return;
TextRun text_run(
text, /* xpos */ 0, /* expansion */ 0,
TextRun::kAllowTrailingExpansion | TextRun::kForbidLeadingExpansion,
direction, false);
text_run.SetNormalizeSpace(true);
FloatRect bbox = font.BoundingBox(text_run);
const FontMetrics& font_metrics = font_data->GetFontMetrics();
advances_ = font.IndividualCharacterAdvances(text_run);
// x direction
width_ = bbox.Width();
FloatRect glyph_bounds;
double real_width = font.Width(text_run, nullptr, &glyph_bounds);
float dx = 0.0f;
if (align == kCenterTextAlign)
dx = real_width / 2.0f;
else if (align == kRightTextAlign ||
(align == kStartTextAlign && direction == TextDirection::kRtl) ||
(align == kEndTextAlign && direction != TextDirection::kRtl))
dx = real_width;
actual_bounding_box_left_ = -glyph_bounds.X() + dx;
actual_bounding_box_right_ = glyph_bounds.MaxX() - dx;
// y direction
const float ascent = font_metrics.FloatAscent();
const float descent = font_metrics.FloatDescent();
const float baseline_y = GetFontBaseline(baseline, *font_data);
font_bounding_box_ascent_ = ascent - baseline_y;
font_bounding_box_descent_ = descent + baseline_y;
actual_bounding_box_ascent_ = -bbox.Y() - baseline_y;
actual_bounding_box_descent_ = bbox.MaxY() + baseline_y;
em_height_ascent_ = font_data->EmHeightAscent() - baseline_y;
em_height_descent_ = font_data->EmHeightDescent() + baseline_y;
// TODO(fserb): hanging/ideographic baselines are broken.
baselines_->setAlphabetic(-baseline_y);
baselines_->setHanging(ascent * kHangingAsPercentOfAscent / 100.0f -
baseline_y);
baselines_->setIdeographic(-descent - baseline_y);
}
} // namespace blink