blob: a9886bcd9284f053494badc2b057c2bfa39edc71 [file] [log] [blame]
// Copyright 2016 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/platform/fonts/shaping/caching_word_shape_iterator.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
namespace blink {
scoped_refptr<const ShapeResult>
CachingWordShapeIterator::ShapeWordWithoutSpacing(const TextRun& word_run,
const Font* font) {
ShapeCacheEntry* cache_entry = shape_cache_->Add(word_run, ShapeCacheEntry());
if (cache_entry && *cache_entry)
return *cache_entry;
const String word_text = word_run.NormalizedUTF16();
HarfBuzzShaper shaper(word_text);
scoped_refptr<const ShapeResult> shape_result =
shaper.Shape(font, word_run.Direction());
if (!shape_result)
return nullptr;
shape_result->SetDeprecatedInkBounds(shape_result->ComputeInkBounds());
if (cache_entry)
*cache_entry = shape_result;
return shape_result;
}
scoped_refptr<const ShapeResult> CachingWordShapeIterator::ShapeWord(
const TextRun& word_run,
const Font* font) {
scoped_refptr<const ShapeResult> result =
ShapeWordWithoutSpacing(word_run, font);
if (LIKELY(!spacing_.HasSpacing()))
return result;
scoped_refptr<const ShapeResult> spacing_result =
result->ApplySpacingToCopy(spacing_, word_run);
FloatRect ink_bounds = spacing_result->ComputeInkBounds();
// Return bounds as is because glyph bounding box is in logical space.
if (spacing_result->Width() >= 0 && ink_bounds.Width() >= 0) {
spacing_result->SetDeprecatedInkBounds(ink_bounds);
return spacing_result;
}
// Negative word-spacing and/or letter-spacing may cause some glyphs to
// overflow the left boundary and result negative measured width. Adjust glyph
// bounds accordingly to cover the overflow.
// The negative width should be clamped to 0 in CSS box model, but it's up to
// caller's responsibility.
float left = std::min(spacing_result->Width(), ink_bounds.Width());
if (left < ink_bounds.X()) {
// The right edge should be the width of the first character in most cases,
// but computing it requires re-measuring bounding box of each glyph. Leave
// it unchanged, which gives an excessive right edge but assures it covers
// all glyphs.
ink_bounds.ShiftXEdgeTo(left);
} else {
ink_bounds.SetWidth(ink_bounds.Width());
}
spacing_result->SetDeprecatedInkBounds(ink_bounds);
return spacing_result;
}
} // namespace blink