reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2006 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef SkScalerContext_DEFINED |
| 18 | #define SkScalerContext_DEFINED |
| 19 | |
| 20 | #include "SkMask.h" |
| 21 | #include "SkMatrix.h" |
| 22 | #include "SkPaint.h" |
| 23 | #include "SkPath.h" |
| 24 | #include "SkPoint.h" |
| 25 | |
| 26 | class SkDescriptor; |
| 27 | class SkMaskFilter; |
| 28 | class SkPathEffect; |
| 29 | class SkRasterizer; |
| 30 | |
| 31 | // needs to be != to any valid SkMask::Format |
| 32 | #define MASK_FORMAT_JUST_ADVANCE (0xFF) |
| 33 | |
| 34 | struct SkGlyph { |
| 35 | void* fImage; |
| 36 | SkPath* fPath; |
| 37 | SkFixed fAdvanceX, fAdvanceY; |
| 38 | |
| 39 | uint32_t fID; |
| 40 | uint16_t fWidth, fHeight; |
| 41 | int16_t fTop, fLeft; |
| 42 | |
| 43 | uint8_t fMaskFormat; |
| 44 | int8_t fRsbDelta, fLsbDelta; // used by auto-kerning |
| 45 | |
| 46 | unsigned rowBytes() const { |
| 47 | unsigned rb = fWidth; |
| 48 | if (SkMask::kBW_Format == fMaskFormat) { |
| 49 | rb = (rb + 7) >> 3; |
| 50 | } else { |
| 51 | rb = SkAlign4(rb); |
| 52 | } |
| 53 | return rb; |
| 54 | } |
| 55 | |
| 56 | bool isJustAdvance() const { |
| 57 | return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; |
| 58 | } |
| 59 | |
| 60 | bool isFullMetrics() const { |
| 61 | return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; |
| 62 | } |
| 63 | |
| 64 | uint16_t getGlyphID() const { |
| 65 | return ID2Code(fID); |
| 66 | } |
| 67 | |
| 68 | unsigned getGlyphID(unsigned baseGlyphCount) const { |
| 69 | unsigned code = ID2Code(fID); |
| 70 | SkASSERT(code >= baseGlyphCount); |
| 71 | return code - baseGlyphCount; |
| 72 | } |
| 73 | |
| 74 | unsigned getSubX() const { |
| 75 | return ID2SubX(fID); |
| 76 | } |
| 77 | |
| 78 | SkFixed getSubXFixed() const { |
| 79 | return SubToFixed(ID2SubX(fID)); |
| 80 | } |
| 81 | |
| 82 | SkFixed getSubYFixed() const { |
| 83 | return SubToFixed(ID2SubY(fID)); |
| 84 | } |
| 85 | |
| 86 | size_t computeImageSize() const; |
| 87 | |
reed@android.com | 62900b4 | 2009-02-11 15:07:19 +0000 | [diff] [blame] | 88 | /** Call this to set all of the metrics fields to 0 (e.g. if the scaler |
| 89 | encounters an error measuring a glyph). Note: this does not alter the |
| 90 | fImage, fPath, fID, fMaskFormat fields. |
| 91 | */ |
| 92 | void zeroMetrics(); |
| 93 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 94 | enum { |
| 95 | kSubBits = 2, |
| 96 | kSubMask = ((1 << kSubBits) - 1), |
| 97 | kSubShift = 24, // must be large enough for glyphs and unichars |
| 98 | kCodeMask = ((1 << kSubShift) - 1), |
| 99 | // relative offsets for X and Y subpixel bits |
| 100 | kSubShiftX = kSubBits, |
| 101 | kSubShiftY = 0 |
| 102 | }; |
| 103 | |
| 104 | static unsigned ID2Code(uint32_t id) { |
| 105 | return id & kCodeMask; |
| 106 | } |
| 107 | |
| 108 | static unsigned ID2SubX(uint32_t id) { |
| 109 | return id >> (kSubShift + kSubShiftX); |
| 110 | } |
| 111 | |
| 112 | static unsigned ID2SubY(uint32_t id) { |
| 113 | return (id >> (kSubShift + kSubShiftY)) & kSubMask; |
| 114 | } |
| 115 | |
| 116 | static unsigned FixedToSub(SkFixed n) { |
| 117 | return (n >> (16 - kSubBits)) & kSubMask; |
| 118 | } |
| 119 | |
| 120 | static SkFixed SubToFixed(unsigned sub) { |
| 121 | SkASSERT(sub <= kSubMask); |
| 122 | return sub << (16 - kSubBits); |
| 123 | } |
| 124 | |
| 125 | static uint32_t MakeID(unsigned code) { |
| 126 | return code; |
| 127 | } |
| 128 | |
| 129 | static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) { |
| 130 | SkASSERT(code <= kCodeMask); |
| 131 | x = FixedToSub(x); |
| 132 | y = FixedToSub(y); |
| 133 | return (x << (kSubShift + kSubShiftX)) | |
| 134 | (y << (kSubShift + kSubShiftY)) | |
| 135 | code; |
| 136 | } |
| 137 | |
| 138 | void toMask(SkMask* mask) const; |
agl@chromium.org | 309485b | 2009-07-21 17:41:32 +0000 | [diff] [blame] | 139 | |
| 140 | /** Given a glyph which is has a mask format of LCD or VerticalLCD, take |
| 141 | the A8 plane in fImage and produce a valid LCD plane from it. |
| 142 | */ |
| 143 | void expandA8ToLCD() const; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 144 | }; |
| 145 | |
| 146 | class SkScalerContext { |
| 147 | public: |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 148 | enum Flags { |
| 149 | kFrameAndFill_Flag = 0x01, |
| 150 | kDevKernText_Flag = 0x02, |
| 151 | kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags |
agl@chromium.org | 309485b | 2009-07-21 17:41:32 +0000 | [diff] [blame] | 152 | kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags |
| 153 | // together, these two flags resulting in a two bit value which matches |
| 154 | // up with the SkPaint::Hinting enum. |
reed@android.com | 36a4c2a | 2009-07-22 19:52:11 +0000 | [diff] [blame^] | 155 | kHintingBit1_Flag = 0x10, |
| 156 | kHintingBit2_Flag = 0x20, |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 157 | }; |
| 158 | struct Rec { |
| 159 | uint32_t fFontID; |
| 160 | SkScalar fTextSize, fPreScaleX, fPreSkewX; |
| 161 | SkScalar fPost2x2[2][2]; |
| 162 | SkScalar fFrameWidth, fMiterLimit; |
agl@chromium.org | 309485b | 2009-07-21 17:41:32 +0000 | [diff] [blame] | 163 | bool fSubpixelPositioning; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 164 | uint8_t fMaskFormat; |
| 165 | uint8_t fStrokeJoin; |
| 166 | uint8_t fFlags; |
agl@chromium.org | 309485b | 2009-07-21 17:41:32 +0000 | [diff] [blame] | 167 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 168 | void getMatrixFrom2x2(SkMatrix*) const; |
| 169 | void getLocalMatrix(SkMatrix*) const; |
| 170 | void getSingleMatrix(SkMatrix*) const; |
agl@chromium.org | 309485b | 2009-07-21 17:41:32 +0000 | [diff] [blame] | 171 | |
| 172 | SkPaint::Hinting getHinting() const { |
| 173 | return static_cast<SkPaint::Hinting>((fFlags >> 4) & 3); |
| 174 | } |
| 175 | |
| 176 | void setHinting(SkPaint::Hinting hinting) { |
reed@android.com | 36a4c2a | 2009-07-22 19:52:11 +0000 | [diff] [blame^] | 177 | fFlags = (fFlags & ~(kHintingBit1_Flag | kHintingBit2_Flag)) | |
agl@chromium.org | 309485b | 2009-07-21 17:41:32 +0000 | [diff] [blame] | 178 | (static_cast<int>(hinting) << 4); |
| 179 | } |
reed@android.com | 36a4c2a | 2009-07-22 19:52:11 +0000 | [diff] [blame^] | 180 | |
| 181 | SkMask::Format getFormat() const { |
| 182 | return static_cast<SkMask::Format>(fMaskFormat); |
| 183 | } |
| 184 | |
| 185 | bool isLCD() const { |
| 186 | return SkMask::FormatIsLCD(this->getFormat()); |
| 187 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 188 | }; |
| 189 | |
| 190 | SkScalerContext(const SkDescriptor* desc); |
| 191 | virtual ~SkScalerContext(); |
| 192 | |
reed@android.com | a14ea0e | 2009-03-17 17:59:53 +0000 | [diff] [blame] | 193 | // remember our glyph offset/base |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 194 | void setBaseGlyphCount(unsigned baseGlyphCount) { |
| 195 | fBaseGlyphCount = baseGlyphCount; |
| 196 | } |
| 197 | |
reed@android.com | a14ea0e | 2009-03-17 17:59:53 +0000 | [diff] [blame] | 198 | /** Return the corresponding glyph for the specified unichar. Since contexts |
| 199 | may be chained (under the hood), the glyphID that is returned may in |
| 200 | fact correspond to a different font/context. In that case, we use the |
| 201 | base-glyph-count to know how to translate back into local glyph space. |
| 202 | */ |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 203 | uint16_t charToGlyphID(SkUnichar uni); |
| 204 | |
| 205 | unsigned getGlyphCount() const { return this->generateGlyphCount(); } |
| 206 | void getAdvance(SkGlyph*); |
| 207 | void getMetrics(SkGlyph*); |
| 208 | void getImage(const SkGlyph&); |
| 209 | void getPath(const SkGlyph&, SkPath*); |
| 210 | void getFontMetrics(SkPaint::FontMetrics* mX, |
| 211 | SkPaint::FontMetrics* mY); |
| 212 | |
| 213 | static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec); |
| 214 | static SkScalerContext* Create(const SkDescriptor*); |
| 215 | |
| 216 | protected: |
| 217 | Rec fRec; |
| 218 | unsigned fBaseGlyphCount; |
| 219 | |
| 220 | virtual unsigned generateGlyphCount() const = 0; |
| 221 | virtual uint16_t generateCharToGlyph(SkUnichar) = 0; |
| 222 | virtual void generateAdvance(SkGlyph*) = 0; |
| 223 | virtual void generateMetrics(SkGlyph*) = 0; |
| 224 | virtual void generateImage(const SkGlyph&) = 0; |
| 225 | virtual void generatePath(const SkGlyph&, SkPath*) = 0; |
| 226 | virtual void generateFontMetrics(SkPaint::FontMetrics* mX, |
| 227 | SkPaint::FontMetrics* mY) = 0; |
| 228 | |
| 229 | private: |
| 230 | SkPathEffect* fPathEffect; |
| 231 | SkMaskFilter* fMaskFilter; |
| 232 | SkRasterizer* fRasterizer; |
| 233 | SkScalar fDevFrameWidth; |
| 234 | |
| 235 | void internalGetPath(const SkGlyph& glyph, SkPath* fillPath, |
| 236 | SkPath* devPath, SkMatrix* fillToDevMatrix); |
| 237 | |
reed@android.com | a14ea0e | 2009-03-17 17:59:53 +0000 | [diff] [blame] | 238 | // return the next context, treating fNextContext as a cache of the answer |
| 239 | SkScalerContext* getNextContext(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 240 | |
reed@android.com | a14ea0e | 2009-03-17 17:59:53 +0000 | [diff] [blame] | 241 | // returns the right context from our link-list for this glyph. If no match |
| 242 | // is found, just returns the original context (this) |
| 243 | SkScalerContext* getGlyphContext(const SkGlyph& glyph); |
| 244 | |
| 245 | // link-list of context, to handle missing chars. null-terminated. |
| 246 | SkScalerContext* fNextContext; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 247 | }; |
| 248 | |
| 249 | #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c') |
| 250 | #define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e') |
| 251 | #define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f') |
| 252 | #define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't') |
| 253 | |
| 254 | #endif |
| 255 | |