blob: bd8d0af85a02c7518f38a6d5d860e3fde88605b7 [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/renderer/rasterizer/skia/font.h"
#include "base/lazy_instance.h"
#include "third_party/skia/include/core/SkPaint.h"
namespace {
const float kXHeightEstimateFactor = 0.56f;
} // namespace
namespace cobalt {
namespace renderer {
namespace rasterizer {
namespace skia {
namespace {
struct NonTrivialStaticFields {
NonTrivialStaticFields() {
default_paint.setAntiAlias(true);
default_paint.setSubpixelText(true);
}
SkPaint default_paint;
private:
DISALLOW_COPY_AND_ASSIGN(NonTrivialStaticFields);
};
// |non_trivial_static_fields| will be lazily created on the first time it's
// accessed.
base::LazyInstance<NonTrivialStaticFields> non_trivial_static_fields =
LAZY_INSTANCE_INITIALIZER;
} // namespace
Font::Font(SkiaTypeface* typeface, SkScalar size)
: typeface_(typeface), size_(size) {
glyph_bounds_thread_checker_.DetachFromThread();
}
SkTypeface_Cobalt* Font::GetSkTypeface() const {
return typeface_->GetSkTypeface();
}
render_tree::TypefaceId Font::GetTypefaceId() const {
return typeface_->GetId();
}
render_tree::FontMetrics Font::GetFontMetrics() const {
SkPaint paint = GetSkPaint();
SkPaint::FontMetrics font_metrics;
paint.getFontMetrics(&font_metrics);
// The x-height is the height of the 'x' glyph. It is used to find the visual
// 'middle' of the font to allow vertical alignment to the middle of the font.
// See also https://en.wikipedia.org/wiki/X-height
float x_height;
if (font_metrics.fXHeight) {
x_height = font_metrics.fXHeight;
} else {
// If the font does not have an 'x' glyph, we need to estimate the value.
// A good estimation is to use 0.56 * the font ascent.
x_height = font_metrics.fAscent * kXHeightEstimateFactor;
}
// In Skia, ascent is negative, while descent and leading are positive.
return render_tree::FontMetrics(-font_metrics.fAscent, font_metrics.fDescent,
font_metrics.fLeading, x_height);
}
render_tree::GlyphIndex Font::GetGlyphForCharacter(int32 utf32_character) {
return typeface_->GetGlyphForCharacter(utf32_character);
}
const math::RectF& Font::GetGlyphBounds(render_tree::GlyphIndex glyph) {
DCHECK(glyph_bounds_thread_checker_.CalledOnValidThread());
// Check to see if the glyph falls within the the first 256 glyphs. These
// characters are part of the primary page and are stored within an array as
// an optimization.
if (glyph < kPrimaryPageSize) {
// The first page is lazily allocated, so we don't use the memory if it's
// never used.
if (!primary_page_glyph_bounds_) {
primary_page_glyph_bounds_.reset(new math::RectF[kPrimaryPageSize]);
// If the page has already been allocated, then check for the glyph's
// bounds having already been set. If this is the case, simply return the
// bounds.
} else if (primary_page_glyph_bounds_bits_[glyph]) {
return primary_page_glyph_bounds_[glyph];
}
// Otherwise, check for the glyph's bounds within the map.
} else {
GlyphToBoundsMap::iterator map_iterator = glyph_to_bounds_map_.find(glyph);
if (map_iterator != glyph_to_bounds_map_.end()) {
return map_iterator->second;
}
}
// If we reach this point, the glyph's bounds were not previously cached and
// need to be calculated them now.
SkPaint paint = GetSkPaint();
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
SkRect skia_bounds;
float width =
paint.measureText(&glyph, sizeof(render_tree::GlyphIndex), &skia_bounds);
// Both cache and return the glyph's bounds.
if (glyph < kPrimaryPageSize) {
primary_page_glyph_bounds_bits_.set(glyph, true);
return primary_page_glyph_bounds_[glyph] =
math::RectF(0, skia_bounds.top(), width, skia_bounds.height());
} else {
return glyph_to_bounds_map_[glyph] =
math::RectF(0, skia_bounds.top(), width, skia_bounds.height());
}
}
float Font::GetGlyphWidth(render_tree::GlyphIndex glyph) {
return GetGlyphBounds(glyph).width();
}
SkPaint Font::GetSkPaint() const {
SkPaint paint(GetDefaultSkPaint());
SkAutoTUnref<SkTypeface> typeface(typeface_->GetSkTypeface());
paint.setTypeface(typeface);
paint.setTextSize(size_);
return paint;
}
const SkPaint& Font::GetDefaultSkPaint() {
return non_trivial_static_fields.Get().default_paint;
}
} // namespace skia
} // namespace rasterizer
} // namespace renderer
} // namespace cobalt