1 /* 2 * Copyright 2009, The Android Open Source Project 3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 29 #include "EmojiFont.h" 30 #include "Font.h" 31 #include "FontData.h" 32 #include "FontFallbackList.h" 33 #include "GraphicsContext.h" 34 #include "GlyphBuffer.h" 35 #include "IntRect.h" 36 #include "PlatformGraphicsContext.h" 37 #include "SkCanvas.h" 38 #include "SkLayerDrawLooper.h" 39 #include "SkPaint.h" 40 #include "SkTemplates.h" 41 #include "SkTypeface.h" 42 #include "SkUtils.h" 43 44 using namespace android; 45 46 namespace WebCore { 47 48 static void updateForFont(SkPaint* paint, const SimpleFontData* font) { 49 font->platformData().setupPaint(paint); 50 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 51 } 52 53 static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc, 54 const SimpleFontData* font) { 55 gc->setupFillPaint(paint); 56 updateForFont(paint, font); 57 return paint; 58 } 59 60 static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc, 61 const SimpleFontData* font) { 62 gc->setupStrokePaint(paint); 63 updateForFont(paint, font); 64 return paint; 65 } 66 67 static bool setupForText(SkPaint* paint, GraphicsContext* gc, 68 const SimpleFontData* font) { 69 int mode = gc->textDrawingMode(); 70 71 if ((mode & (cTextFill | cTextStroke)) == (cTextFill | cTextStroke)) { 72 SkLayerDrawLooper* looper = new SkLayerDrawLooper; 73 paint->setLooper(looper)->unref(); 74 75 // we clear the looper, in case we have a shadow 76 77 SkPaint* fillP = NULL; 78 SkPaint* strokeP = NULL; 79 if (gc->willStroke()) { 80 strokeP = setupStroke(looper->addLayer(), gc, font); 81 strokeP->setLooper(NULL); 82 } 83 if (gc->willFill()) { 84 fillP = setupFill(looper->addLayer(), gc, font); 85 fillP->setLooper(NULL); 86 } 87 88 SkPaint shadowPaint; 89 SkPoint offset; 90 if (gc->setupShadowPaint(&shadowPaint, &offset)) { 91 SkPaint* p = looper->addLayer(offset.fX, offset.fY); 92 *p = shadowPaint; 93 if (strokeP && !fillP) { 94 // stroke the shadow if we have stroke but no fill 95 p->setStyle(SkPaint::kStroke_Style); 96 p->setStrokeWidth(strokeP->getStrokeWidth()); 97 } 98 updateForFont(p, font); 99 } 100 } else if (mode & cTextFill) { 101 (void)setupFill(paint, gc, font); 102 } else if (mode & cTextStroke) { 103 (void)setupStroke(paint, gc, font); 104 } else { 105 return false; 106 } 107 return true; 108 } 109 110 bool Font::canReturnFallbackFontsForComplexText() 111 { 112 return false; 113 } 114 115 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, 116 const GlyphBuffer& glyphBuffer, int from, int numGlyphs, 117 const FloatPoint& point) const 118 { 119 // compile-time assert 120 SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); 121 122 SkPaint paint; 123 if (!setupForText(&paint, gc, font)) { 124 return; 125 } 126 127 SkScalar x = SkFloatToScalar(point.x()); 128 SkScalar y = SkFloatToScalar(point.y()); 129 const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); 130 const GlyphBufferAdvance* adv = glyphBuffer.advances(from); 131 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); 132 SkPoint* pos = storage.get(); 133 134 SkCanvas* canvas = gc->platformContext()->mCanvas; 135 136 /* We need an array of [x,y,x,y,x,y,...], but webkit is giving us 137 point.xy + [width, height, width, height, ...], so we have to convert 138 */ 139 140 if (EmojiFont::IsAvailable()) { 141 // set filtering, to make scaled images look nice(r) 142 paint.setFilterBitmap(true); 143 144 int localIndex = 0; 145 int localCount = 0; 146 for (int i = 0; i < numGlyphs; i++) { 147 if (EmojiFont::IsEmojiGlyph(glyphs[i])) { 148 if (localCount) 149 canvas->drawPosText(&glyphs[localIndex], 150 localCount * sizeof(uint16_t), 151 &pos[localIndex], paint); 152 EmojiFont::Draw(canvas, glyphs[i], x, y, paint); 153 // reset local index/count track for "real" glyphs 154 localCount = 0; 155 localIndex = i + 1; 156 } else { 157 pos[i].set(x, y); 158 localCount += 1; 159 } 160 x += SkFloatToScalar(adv[i].width()); 161 y += SkFloatToScalar(adv[i].height()); 162 } 163 // draw the last run of glyphs (if any) 164 if (localCount) 165 canvas->drawPosText(&glyphs[localIndex], 166 localCount * sizeof(uint16_t), 167 &pos[localIndex], paint); 168 } else { 169 for (int i = 0; i < numGlyphs; i++) { 170 pos[i].set(x, y); 171 x += SkFloatToScalar(adv[i].width()); 172 y += SkFloatToScalar(adv[i].height()); 173 } 174 canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint); 175 } 176 } 177 178 FloatRect Font::selectionRectForComplexText(const TextRun& run, 179 const IntPoint& point, int h, int, int) const 180 { 181 SkPaint paint; 182 SkScalar width, left; 183 SkPaint::FontMetrics metrics; 184 185 primaryFont()->platformData().setupPaint(&paint); 186 187 width = paint.measureText(run.characters(), run.length() << 1); 188 SkScalar spacing = paint.getFontMetrics(&metrics); 189 190 return FloatRect(point.x(), 191 point.y(), 192 roundf(SkScalarToFloat(width)), 193 roundf(SkScalarToFloat(spacing))); 194 } 195 196 void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, 197 FloatPoint const& point, int, int) const 198 { 199 SkCanvas* canvas = gc->platformContext()->mCanvas; 200 SkPaint paint; 201 202 if (!setupForText(&paint, gc, primaryFont())) { 203 return; 204 } 205 206 // go to chars, instead of glyphs, which was set by setupForText() 207 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 208 209 canvas->drawText(run.characters(), run.length() << 1, 210 SkFloatToScalar(point.x()), SkFloatToScalar(point.y()), 211 paint); 212 } 213 214 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const 215 { 216 SkPaint paint; 217 218 primaryFont()->platformData().setupPaint(&paint); 219 220 //printf("--------- complext measure %d chars\n", run.to() - run.from()); 221 222 SkScalar width = paint.measureText(run.characters(), run.length() << 1); 223 return SkScalarToFloat(width); 224 } 225 226 int Font::offsetForPositionForComplexText(const TextRun& run, int x, 227 bool includePartialGlyphs) const 228 { 229 SkPaint paint; 230 int count = run.length(); 231 SkAutoSTMalloc<64, SkScalar> storage(count); 232 SkScalar* widths = storage.get(); 233 234 primaryFont()->platformData().setupPaint(&paint); 235 236 count = paint.getTextWidths(run.characters(), count << 1, widths); 237 238 if (count > 0) 239 { 240 SkScalar pos = 0; 241 for (int i = 0; i < count; i++) 242 { 243 if (x < SkScalarRound(pos + SkScalarHalf(widths[i]))) 244 return i; 245 pos += widths[i]; 246 } 247 } 248 return count; 249 } 250 251 } 252