| /* |
| * Copyright (c) 2007, 2008, 2010 Google 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: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * 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. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "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 THE COPYRIGHT |
| * OWNER 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 "core/platform/graphics/Font.h" |
| |
| #include "platform/NotImplemented.h" |
| #include "core/platform/graphics/GlyphBuffer.h" |
| #include "core/platform/graphics/GraphicsContext.h" |
| #include "core/platform/graphics/SimpleFontData.h" |
| #include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h" |
| #include "platform/geometry/FloatRect.h" |
| |
| #include "SkPaint.h" |
| #include "SkTemplates.h" |
| |
| #include "wtf/unicode/Unicode.h" |
| |
| namespace WebCore { |
| |
| bool Font::canReturnFallbackFontsForComplexText() |
| { |
| return false; |
| } |
| |
| bool Font::canExpandAroundIdeographsInComplexText() |
| { |
| return false; |
| } |
| |
| void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, |
| const GlyphBuffer& glyphBuffer, int from, int numGlyphs, |
| const FloatPoint& point, const FloatRect& textRect) const { |
| SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert |
| |
| const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); |
| SkScalar x = SkFloatToScalar(point.x()); |
| SkScalar y = SkFloatToScalar(point.y()); |
| |
| // FIXME: text rendering speed: |
| // Android has code in their WebCore fork to special case when the |
| // GlyphBuffer has no advances other than the defaults. In that case the |
| // text drawing can proceed faster. However, it's unclear when those |
| // patches may be upstreamed to WebKit so we always use the slower path |
| // here. |
| const GlyphBufferAdvance* adv = glyphBuffer.advances(from); |
| SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs); |
| SkPoint* pos = storage.get(); |
| SkPoint* vPosBegin = storage2.get(); |
| SkPoint* vPosEnd = storage3.get(); |
| |
| bool isVertical = font->platformData().orientation() == Vertical; |
| SkScalar verticalPosCompensation = isVertical ? SkFloatToScalar((font->fontMetrics().floatHeight() - font->fontMetrics().floatAscent()) / 2) : 0; |
| for (int i = 0; i < numGlyphs; i++) { |
| SkScalar myWidth = SkFloatToScalar(adv[i].width()); |
| pos[i].set(x, y); |
| if (isVertical) { |
| // In vertical mode, we need to align the left of ideographics to the vertical baseline. |
| // (Note vertical/horizontal are in absolute orientation, that is, here x is vertical.) |
| // However, when the glyph is drawn in drawTextOnPath(), the baseline is the horizontal path, |
| // so the ideographics will look shifted to the bottom-right direction because the ascent is |
| // applied vertically. Compensate the position so that ascent will look like to be applied |
| // horizontally. |
| SkScalar bottom = x + myWidth - verticalPosCompensation; |
| SkScalar left = y + verticalPosCompensation; |
| vPosBegin[i].set(bottom, left); |
| vPosEnd[i].set(bottom, left - myWidth); |
| } |
| x += myWidth; |
| y += SkFloatToScalar(adv[i].height()); |
| } |
| |
| TextDrawingModeFlags textMode = gc->textDrawingMode(); |
| |
| // We draw text up to two times (once for fill, once for stroke). |
| if (textMode & TextModeFill) { |
| SkPaint paint; |
| gc->setupPaintForFilling(&paint); |
| font->platformData().setupPaint(&paint); |
| gc->adjustTextRenderMode(&paint); |
| paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| |
| if (isVertical) { |
| SkPath path; |
| for (int i = 0; i < numGlyphs; ++i) { |
| path.reset(); |
| path.moveTo(vPosBegin[i]); |
| path.lineTo(vPosEnd[i]); |
| gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint); |
| } |
| } else |
| gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint); |
| } |
| |
| if ((textMode & TextModeStroke) |
| && gc->strokeStyle() != NoStroke |
| && gc->strokeThickness() > 0) { |
| |
| SkPaint paint; |
| gc->setupPaintForStroking(&paint); |
| font->platformData().setupPaint(&paint); |
| gc->adjustTextRenderMode(&paint); |
| paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| |
| if (textMode & TextModeFill) { |
| // If we also filled, we don't want to draw shadows twice. |
| // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. |
| // Since we use the looper for shadows, we remove it (if any) now. |
| paint.setLooper(0); |
| } |
| |
| if (isVertical) { |
| SkPath path; |
| for (int i = 0; i < numGlyphs; ++i) { |
| path.reset(); |
| path.moveTo(vPosBegin[i]); |
| path.lineTo(vPosEnd[i]); |
| gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint); |
| } |
| } else |
| gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint); |
| } |
| } |
| |
| void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const |
| { |
| if (!runInfo.run.length()) |
| return; |
| |
| TextDrawingModeFlags textMode = gc->textDrawingMode(); |
| bool fill = textMode & TextModeFill; |
| bool stroke = (textMode & TextModeStroke) |
| && gc->strokeStyle() != NoStroke |
| && gc->strokeThickness() > 0; |
| |
| if (!fill && !stroke) |
| return; |
| |
| GlyphBuffer glyphBuffer; |
| HarfBuzzShaper shaper(this, runInfo.run); |
| shaper.setDrawRange(runInfo.from, runInfo.to); |
| if (!shaper.shape(&glyphBuffer)) |
| return; |
| FloatPoint adjustedPoint = shaper.adjustStartPoint(point); |
| drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint); |
| } |
| |
| void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const |
| { |
| notImplemented(); |
| } |
| |
| float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const |
| { |
| HarfBuzzShaper shaper(this, run); |
| if (!shaper.shape()) |
| return 0; |
| return shaper.totalWidth(); |
| } |
| |
| // Return the code point index for the given |x| offset into the text run. |
| int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, |
| bool includePartialGlyphs) const |
| { |
| HarfBuzzShaper shaper(this, run); |
| if (!shaper.shape()) |
| return 0; |
| return shaper.offsetForPosition(xFloat); |
| } |
| |
| // Return the rectangle for selecting the given range of code-points in the TextRun. |
| FloatRect Font::selectionRectForComplexText(const TextRun& run, |
| const FloatPoint& point, int height, |
| int from, int to) const |
| { |
| HarfBuzzShaper shaper(this, run); |
| if (!shaper.shape()) |
| return FloatRect(); |
| return shaper.selectionRect(point, height, from, to); |
| } |
| |
| } // namespace WebCore |