1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkFont.h"
9#include "SkTypeface.h"
10#include "SkUtils.h"
11
12SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType mt,
13               uint32_t flags)
14    : fTypeface(face ? std::move(face) : SkTypeface::MakeDefault())
15    , fSize(size)
16    , fScaleX(scaleX)
17    , fSkewX(skewX)
18    , fFlags(flags)
19    , fMaskType(SkToU8(mt))
20{
21    SkASSERT(size > 0);
22    SkASSERT(scaleX > 0);
23    SkASSERT(SkScalarIsFinite(skewX));
24    SkASSERT(0 == (flags & ~kAllFlags));
25}
26
27sk_sp<SkFont> SkFont::Make(sk_sp<SkTypeface> face, SkScalar size, SkScalar scaleX, SkScalar skewX,
28                           MaskType mt, uint32_t flags) {
29    if (size <= 0 || !SkScalarIsFinite(size)) {
30        return nullptr;
31    }
32    if (scaleX <= 0 || !SkScalarIsFinite(scaleX)) {
33        return nullptr;
34    }
35    if (!SkScalarIsFinite(skewX)) {
36        return nullptr;
37    }
38    flags &= kAllFlags;
39    return sk_sp<SkFont>(new SkFont(std::move(face), size, scaleX, skewX, mt, flags));
40}
41
42sk_sp<SkFont> SkFont::Make(sk_sp<SkTypeface> face, SkScalar size, MaskType mt, uint32_t flags) {
43    return SkFont::Make(std::move(face), size, 1, 0, mt, flags);
44}
45
46sk_sp<SkFont> SkFont::makeWithSize(SkScalar newSize) const {
47    return SkFont::Make(sk_ref_sp(this->getTypeface()), newSize, this->getScaleX(),
48                        this->getSkewX(), this->getMaskType(), this->getFlags());
49}
50
51sk_sp<SkFont> SkFont::makeWithFlags(uint32_t newFlags) const {
52    return SkFont::Make(sk_ref_sp(this->getTypeface()), this->getSize(), this->getScaleX(),
53                        this->getSkewX(), this->getMaskType(), newFlags);
54}
55///////////////////////////////////////////////////////////////////////////////////////////////////
56
57int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding,
58                         uint16_t glyphs[], int maxGlyphCount) const {
59    if (0 == byteLength) {
60        return 0;
61    }
62
63    SkASSERT(text);
64
65    int count = 0;  // fix uninitialized warning (even though the switch is complete!)
66
67    switch (encoding) {
68        case kUTF8_SkTextEncoding:
69            count = SkUTF8_CountUnichars((const char*)text, byteLength);
70            break;
71        case kUTF16_SkTextEncoding:
72            count = SkUTF16_CountUnichars((const uint16_t*)text, SkToInt(byteLength >> 1));
73            break;
74        case kUTF32_SkTextEncoding:
75            count = SkToInt(byteLength >> 2);
76            break;
77        case kGlyphID_SkTextEncoding:
78            count = SkToInt(byteLength >> 1);
79            break;
80    }
81    if (!glyphs) {
82        return count;
83    }
84
85    // TODO: unify/eliminate SkTypeface::Encoding with SkTextEncoding
86    SkTypeface::Encoding typefaceEncoding;
87    switch (encoding) {
88        case kUTF8_SkTextEncoding:
89            typefaceEncoding = SkTypeface::kUTF8_Encoding;
90            break;
91        case kUTF16_SkTextEncoding:
92            typefaceEncoding = SkTypeface::kUTF16_Encoding;
93            break;
94        case kUTF32_SkTextEncoding:
95            typefaceEncoding = SkTypeface::kUTF32_Encoding;
96            break;
97        default:
98            SkASSERT(kGlyphID_SkTextEncoding == encoding);
99            // we can early exit, since we already have glyphIDs
100            memcpy(glyphs, text, count << 1);
101            return count;
102    }
103
104    (void)fTypeface->charsToGlyphs(text, typefaceEncoding, glyphs, count);
105    return count;
106}
107
108SkScalar SkFont::measureText(const void* text, size_t byteLength, SkTextEncoding encoding) const {
109    // TODO: need access to the cache
110    return -1;
111}
112
113///////////////////////////////////////////////////////////////////////////////////////////////////
114
115#include "SkPaint.h"
116
117sk_sp<SkFont> SkFont::Testing_CreateFromPaint(const SkPaint& paint) {
118    uint32_t flags = 0;
119    if (paint.isVerticalText()) {
120        flags |= kVertical_Flag;
121    }
122    if (paint.isEmbeddedBitmapText()) {
123        flags |= kEmbeddedBitmaps_Flag;
124    }
125    if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) {
126        flags |= kGenA8FromLCD_Flag;
127    }
128    if (paint.isFakeBoldText()) {
129        flags |= kEmbolden_Flag;
130    }
131
132    if (SkPaint::kFull_Hinting == paint.getHinting()) {
133        flags |= kEnableByteCodeHints_Flag;
134    }
135    if (paint.isAutohinted()) {
136        flags |= kEnableAutoHints_Flag;
137    }
138    if (paint.isSubpixelText() || paint.isLinearText()) {
139        // this is our default
140    } else {
141        flags |= kUseNonlinearMetrics_Flag;
142    }
143
144    MaskType maskType = SkFont::kBW_MaskType;
145    if (paint.isAntiAlias()) {
146        maskType = paint.isLCDRenderText() ? kLCD_MaskType : kA8_MaskType;
147    }
148
149    return Make(sk_ref_sp(paint.getTypeface()), paint.getTextSize(), paint.getTextScaleX(),
150                paint.getTextSkewX(), maskType, flags);
151}
152