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 "FontFallbackList.h" 30 #include "GlyphBuffer.h" 31 #include "GraphicsContext.h" 32 #include "IntRect.h" 33 #include "SimpleFontData.h" 34 #include "TextRun.h" 35 #include <wtf/MathExtras.h> 36 37 using namespace std; 38 39 namespace WebCore { 40 41 FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, 42 int from, int to) const 43 { 44 ComplexTextController controller(this, run); 45 controller.advance(from); 46 float beforeWidth = controller.runWidthSoFar(); 47 controller.advance(to); 48 float afterWidth = controller.runWidthSoFar(); 49 50 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning 51 if (run.rtl()) { 52 float totalWidth = controller.totalWidth(); 53 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); 54 } 55 56 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); 57 } 58 59 float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const 60 { 61 float initialAdvance; 62 63 ComplexTextController controller(this, run, false, 0, forTextEmphasis); 64 controller.advance(from); 65 float beforeWidth = controller.runWidthSoFar(); 66 controller.advance(to, &glyphBuffer); 67 68 if (glyphBuffer.isEmpty()) 69 return 0; 70 71 float afterWidth = controller.runWidthSoFar(); 72 73 if (run.rtl()) { 74 initialAdvance = controller.totalWidth() - afterWidth; 75 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) 76 glyphBuffer.swap(i, end); 77 } else 78 initialAdvance = beforeWidth; 79 80 return initialAdvance; 81 } 82 83 void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const 84 { 85 // This glyph buffer holds our glyphs + advances + font data for each glyph. 86 GlyphBuffer glyphBuffer; 87 88 float startX = point.x() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer); 89 90 // We couldn't generate any glyphs for the run. Give up. 91 if (glyphBuffer.isEmpty()) 92 return; 93 94 // Draw the glyph buffer now at the starting point returned in startX. 95 FloatPoint startPoint(startX, point.y()); 96 drawGlyphBuffer(context, glyphBuffer, startPoint); 97 } 98 99 void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const 100 { 101 GlyphBuffer glyphBuffer; 102 float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis); 103 104 if (glyphBuffer.isEmpty()) 105 return; 106 107 drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); 108 } 109 110 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 111 { 112 ComplexTextController controller(this, run, true, fallbackFonts); 113 if (glyphOverflow) { 114 glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); 115 glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); 116 glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); 117 glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); 118 } 119 return controller.totalWidth(); 120 } 121 122 int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool includePartialGlyphs) const 123 { 124 ComplexTextController controller(this, run); 125 return controller.offsetForPosition(x, includePartialGlyphs); 126 } 127 128 } // namespace WebCore 129