1/* 2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include "config.h" 26#include "Font.h" 27 28#include "ComplexTextController.h" 29#include "FontGlyphs.h" 30#include "GlyphBuffer.h" 31#include "GraphicsContext.h" 32#include "IntRect.h" 33#include "LayoutRect.h" 34#include "SimpleFontData.h" 35#include "TextRun.h" 36#include <wtf/MathExtras.h> 37 38namespace WebCore { 39 40void Font::adjustSelectionRectForComplexText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const 41{ 42 ComplexTextController controller(this, run); 43 controller.advance(from); 44 float beforeWidth = controller.runWidthSoFar(); 45 controller.advance(to); 46 float afterWidth = controller.runWidthSoFar(); 47 48 if (run.rtl()) 49 selectionRect.move(controller.totalWidth() - afterWidth, 0); 50 else 51 selectionRect.move(beforeWidth, 0); 52 selectionRect.setWidth(afterWidth - beforeWidth); 53} 54 55float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const 56{ 57 float initialAdvance; 58 59 ComplexTextController controller(this, run, false, 0, forTextEmphasis); 60 controller.advance(from); 61 float beforeWidth = controller.runWidthSoFar(); 62 controller.advance(to, &glyphBuffer); 63 64 if (glyphBuffer.isEmpty()) 65 return 0; 66 67 float afterWidth = controller.runWidthSoFar(); 68 69 if (run.rtl()) { 70 initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth; 71 glyphBuffer.reverse(0, glyphBuffer.size()); 72 } else 73 initialAdvance = beforeWidth; 74 75 return initialAdvance; 76} 77 78float Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const 79{ 80 // This glyph buffer holds our glyphs + advances + font data for each glyph. 81 GlyphBuffer glyphBuffer; 82 83 float startX = point.x() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer); 84 85 // We couldn't generate any glyphs for the run. Give up. 86 if (glyphBuffer.isEmpty()) 87 return 0; 88 89 // Draw the glyph buffer now at the starting point returned in startX. 90 FloatPoint startPoint(startX, point.y()); 91 drawGlyphBuffer(context, run, glyphBuffer, startPoint); 92 93 return startPoint.x() - startX; 94} 95 96void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const 97{ 98 GlyphBuffer glyphBuffer; 99 float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis); 100 101 if (glyphBuffer.isEmpty()) 102 return; 103 104 drawEmphasisMarks(context, run, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); 105} 106 107float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 108{ 109 ComplexTextController controller(this, run, true, fallbackFonts); 110 if (glyphOverflow) { 111 glyphOverflow->top = std::max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); 112 glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); 113 glyphOverflow->left = std::max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); 114 glyphOverflow->right = std::max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); 115 } 116 return controller.totalWidth(); 117} 118 119int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool includePartialGlyphs) const 120{ 121 ComplexTextController controller(this, run); 122 return controller.offsetForPosition(x, includePartialGlyphs); 123} 124 125const SimpleFontData* Font::fontDataForCombiningCharacterSequence(const UChar* characters, size_t length, FontDataVariant variant) const 126{ 127 UChar32 baseCharacter; 128 size_t baseCharacterLength = 0; 129 U16_NEXT(characters, baseCharacterLength, length, baseCharacter); 130 131 GlyphData baseCharacterGlyphData = glyphDataForCharacter(baseCharacter, false, variant); 132 133 if (!baseCharacterGlyphData.glyph) 134 return 0; 135 136 if (length == baseCharacterLength) 137 return baseCharacterGlyphData.fontData; 138 139 bool triedBaseCharacterFontData = false; 140 141 unsigned i = 0; 142 for (const FontData* fontData = fontDataAt(0); fontData; fontData = fontDataAt(++i)) { 143 const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(baseCharacter); 144#if PLATFORM(IOS) 145 if (baseCharacter >= 0x0600 && baseCharacter <= 0x06ff && simpleFontData->shouldNotBeUsedForArabic()) 146 continue; 147#endif 148 if (variant == NormalVariant) { 149 if (simpleFontData->platformData().orientation() == Vertical) { 150 if (isCJKIdeographOrSymbol(baseCharacter) && !simpleFontData->hasVerticalGlyphs()) { 151 variant = BrokenIdeographVariant; 152 simpleFontData = simpleFontData->brokenIdeographFontData().get(); 153 } else if (m_fontDescription.nonCJKGlyphOrientation() == NonCJKGlyphOrientationVerticalRight) { 154 SimpleFontData* verticalRightFontData = simpleFontData->verticalRightOrientationFontData().get(); 155 Glyph verticalRightGlyph = verticalRightFontData->glyphForCharacter(baseCharacter); 156 if (verticalRightGlyph == baseCharacterGlyphData.glyph) 157 simpleFontData = verticalRightFontData; 158 } else { 159 SimpleFontData* uprightFontData = simpleFontData->uprightOrientationFontData().get(); 160 Glyph uprightGlyph = uprightFontData->glyphForCharacter(baseCharacter); 161 if (uprightGlyph != baseCharacterGlyphData.glyph) 162 simpleFontData = uprightFontData; 163 } 164 } 165 } else { 166 if (const SimpleFontData* variantFontData = simpleFontData->variantFontData(m_fontDescription, variant).get()) 167 simpleFontData = variantFontData; 168 } 169 170 if (simpleFontData == baseCharacterGlyphData.fontData) 171 triedBaseCharacterFontData = true; 172 173 if (simpleFontData->canRenderCombiningCharacterSequence(characters, length)) 174 return simpleFontData; 175 } 176 177 if (!triedBaseCharacterFontData && baseCharacterGlyphData.fontData && baseCharacterGlyphData.fontData->canRenderCombiningCharacterSequence(characters, length)) 178 return baseCharacterGlyphData.fontData; 179 180 return SimpleFontData::systemFallback(); 181} 182 183} // namespace WebCore 184