| /* |
| * Copyright 2009, The Android Open Source Project |
| * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include "EmojiFont.h" |
| #include "Font.h" |
| #include "FontData.h" |
| #include "FontFallbackList.h" |
| #include "GraphicsContext.h" |
| #include "GlyphBuffer.h" |
| #include "IntRect.h" |
| #include "PlatformGraphicsContext.h" |
| #include "SkCanvas.h" |
| #include "SkLayerDrawLooper.h" |
| #include "SkPaint.h" |
| #include "SkTemplates.h" |
| #include "SkTypeface.h" |
| #include "SkUtils.h" |
| |
| using namespace android; |
| |
| namespace WebCore { |
| |
| static void updateForFont(SkPaint* paint, const SimpleFontData* font) { |
| font->platformData().setupPaint(paint); |
| paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| } |
| |
| static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc, |
| const SimpleFontData* font) { |
| gc->setupFillPaint(paint); |
| updateForFont(paint, font); |
| return paint; |
| } |
| |
| static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc, |
| const SimpleFontData* font) { |
| gc->setupStrokePaint(paint); |
| updateForFont(paint, font); |
| return paint; |
| } |
| |
| static bool setupForText(SkPaint* paint, GraphicsContext* gc, |
| const SimpleFontData* font) { |
| int mode = gc->textDrawingMode(); |
| |
| if ((mode & (cTextFill | cTextStroke)) == (cTextFill | cTextStroke)) { |
| SkLayerDrawLooper* looper = new SkLayerDrawLooper; |
| paint->setLooper(looper)->unref(); |
| |
| // we clear the looper, in case we have a shadow |
| |
| SkPaint* fillP = NULL; |
| SkPaint* strokeP = NULL; |
| if (gc->willStroke()) { |
| strokeP = setupStroke(looper->addLayer(), gc, font); |
| strokeP->setLooper(NULL); |
| } |
| if (gc->willFill()) { |
| fillP = setupFill(looper->addLayer(), gc, font); |
| fillP->setLooper(NULL); |
| } |
| |
| SkPaint shadowPaint; |
| SkPoint offset; |
| if (gc->setupShadowPaint(&shadowPaint, &offset)) { |
| SkPaint* p = looper->addLayer(offset.fX, offset.fY); |
| *p = shadowPaint; |
| if (strokeP && !fillP) { |
| // stroke the shadow if we have stroke but no fill |
| p->setStyle(SkPaint::kStroke_Style); |
| p->setStrokeWidth(strokeP->getStrokeWidth()); |
| } |
| updateForFont(p, font); |
| } |
| } else if (mode & cTextFill) { |
| (void)setupFill(paint, gc, font); |
| } else if (mode & cTextStroke) { |
| (void)setupStroke(paint, gc, font); |
| } else { |
| return false; |
| } |
| return true; |
| } |
| |
| bool Font::canReturnFallbackFontsForComplexText() |
| { |
| return false; |
| } |
| |
| void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, |
| const GlyphBuffer& glyphBuffer, int from, int numGlyphs, |
| const FloatPoint& point) const |
| { |
| // compile-time assert |
| SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); |
| |
| SkPaint paint; |
| if (!setupForText(&paint, gc, font)) { |
| return; |
| } |
| |
| SkScalar x = SkFloatToScalar(point.x()); |
| SkScalar y = SkFloatToScalar(point.y()); |
| const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); |
| const GlyphBufferAdvance* adv = glyphBuffer.advances(from); |
| SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); |
| SkPoint* pos = storage.get(); |
| |
| SkCanvas* canvas = gc->platformContext()->mCanvas; |
| |
| /* We need an array of [x,y,x,y,x,y,...], but webkit is giving us |
| point.xy + [width, height, width, height, ...], so we have to convert |
| */ |
| |
| if (EmojiFont::IsAvailable()) { |
| // set filtering, to make scaled images look nice(r) |
| paint.setFilterBitmap(true); |
| |
| int localIndex = 0; |
| int localCount = 0; |
| for (int i = 0; i < numGlyphs; i++) { |
| if (EmojiFont::IsEmojiGlyph(glyphs[i])) { |
| if (localCount) |
| canvas->drawPosText(&glyphs[localIndex], |
| localCount * sizeof(uint16_t), |
| &pos[localIndex], paint); |
| EmojiFont::Draw(canvas, glyphs[i], x, y, paint); |
| // reset local index/count track for "real" glyphs |
| localCount = 0; |
| localIndex = i + 1; |
| } else { |
| pos[i].set(x, y); |
| localCount += 1; |
| } |
| x += SkFloatToScalar(adv[i].width()); |
| y += SkFloatToScalar(adv[i].height()); |
| } |
| // draw the last run of glyphs (if any) |
| if (localCount) |
| canvas->drawPosText(&glyphs[localIndex], |
| localCount * sizeof(uint16_t), |
| &pos[localIndex], paint); |
| } else { |
| for (int i = 0; i < numGlyphs; i++) { |
| pos[i].set(x, y); |
| x += SkFloatToScalar(adv[i].width()); |
| y += SkFloatToScalar(adv[i].height()); |
| } |
| canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint); |
| } |
| } |
| |
| FloatRect Font::selectionRectForComplexText(const TextRun& run, |
| const IntPoint& point, int h, int, int) const |
| { |
| SkPaint paint; |
| SkScalar width, left; |
| SkPaint::FontMetrics metrics; |
| |
| primaryFont()->platformData().setupPaint(&paint); |
| |
| width = paint.measureText(run.characters(), run.length() << 1); |
| SkScalar spacing = paint.getFontMetrics(&metrics); |
| |
| return FloatRect(point.x(), |
| point.y() - floorf(SkScalarToFloat(-metrics.fAscent)), |
| roundf(SkScalarToFloat(width)), |
| roundf(SkScalarToFloat(spacing))); |
| } |
| |
| void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, |
| FloatPoint const& point, int, int) const |
| { |
| SkCanvas* canvas = gc->platformContext()->mCanvas; |
| SkPaint paint; |
| |
| if (!setupForText(&paint, gc, primaryFont())) { |
| return; |
| } |
| |
| // go to chars, instead of glyphs, which was set by setupForText() |
| paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); |
| |
| canvas->drawText(run.characters(), run.length() << 1, |
| SkFloatToScalar(point.x()), SkFloatToScalar(point.y()), |
| paint); |
| } |
| |
| float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const |
| { |
| SkPaint paint; |
| |
| primaryFont()->platformData().setupPaint(&paint); |
| |
| //printf("--------- complext measure %d chars\n", run.to() - run.from()); |
| |
| SkScalar width = paint.measureText(run.characters(), run.length() << 1); |
| return SkScalarToFloat(width); |
| } |
| |
| int Font::offsetForPositionForComplexText(const TextRun& run, int x, |
| bool includePartialGlyphs) const |
| { |
| SkPaint paint; |
| int count = run.length(); |
| SkAutoSTMalloc<64, SkScalar> storage(count); |
| SkScalar* widths = storage.get(); |
| |
| primaryFont()->platformData().setupPaint(&paint); |
| |
| count = paint.getTextWidths(run.characters(), count << 1, widths); |
| |
| if (count > 0) |
| { |
| SkScalar pos = 0; |
| for (int i = 0; i < count; i++) |
| { |
| if (x < SkScalarRound(pos + SkScalarHalf(widths[i]))) |
| return i; |
| pos += widths[i]; |
| } |
| } |
| return count; |
| } |
| |
| } |