e9c15417f17e0c24915151924d18b4282fca1ec4
[WebKit-https.git] / WebCore / platform / graphics / chromium / FontLinux.cpp
1 /*
2  * Copyright (c) 2007, 2008, Google 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 are
6  * met:
7  * 
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
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "Font.h"
33
34 #include "FloatRect.h"
35 #include "GlyphBuffer.h"
36 #include "GraphicsContext.h"
37 #include "NotImplemented.h"
38 #include "PlatformContextSkia.h"
39 #include "SimpleFontData.h"
40
41 #include "SkCanvas.h"
42 #include "SkPaint.h"
43 #include "SkTemplates.h"
44 #include "SkTypeface.h"
45 #include "SkUtils.h"
46
47 extern "C" {
48 #include "harfbuzz-shaper.h"
49 #include "harfbuzz-unicode.h"
50 }
51
52 namespace WebCore {
53
54 bool Font::canReturnFallbackFontsForComplexText()
55 {
56     return false;
57 }
58
59 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
60                       const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
61                       const FloatPoint& point) const {
62     SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
63
64     const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
65     SkScalar x = SkFloatToScalar(point.x());
66     SkScalar y = SkFloatToScalar(point.y());
67
68     // FIXME: text rendering speed:
69     // Android has code in their WebCore fork to special case when the
70     // GlyphBuffer has no advances other than the defaults. In that case the
71     // text drawing can proceed faster. However, it's unclear when those
72     // patches may be upstreamed to WebKit so we always use the slower path
73     // here.
74     const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
75     SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
76     SkPoint* pos = storage.get();
77
78     for (int i = 0; i < numGlyphs; i++) {
79         pos[i].set(x, y);
80         x += SkFloatToScalar(adv[i].width());
81         y += SkFloatToScalar(adv[i].height());
82     }
83
84     SkCanvas* canvas = gc->platformContext()->canvas();
85     int textMode = gc->platformContext()->getTextDrawingMode();
86
87     // We draw text up to two times (once for fill, once for stroke).
88     if (textMode & cTextFill) {
89         SkPaint paint;
90         gc->platformContext()->setupPaintForFilling(&paint);
91         font->platformData().setupPaint(&paint);
92         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
93         paint.setColor(gc->fillColor().rgb());
94         canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
95     }
96
97     if ((textMode & cTextStroke)
98         && gc->platformContext()->getStrokeStyle() != NoStroke
99         && gc->platformContext()->getStrokeThickness() > 0) {
100
101         SkPaint paint;
102         gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
103         font->platformData().setupPaint(&paint);
104         paint.setFlags(SkPaint::kAntiAlias_Flag);
105         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
106         paint.setColor(gc->strokeColor().rgb());
107
108         if (textMode & cTextFill) {
109             // If we also filled, we don't want to draw shadows twice.
110             // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
111             paint.setLooper(0)->safeUnref();
112         }
113
114         canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
115     }
116 }
117
118 extern const HB_FontClass harfbuzzSkiaClass;
119 extern HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
120
121 // Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
122 // handle subpixel positioning so this function is used to truncate Harfbuzz
123 // values to a number of pixels.
124 static int truncateFixedPointToInteger(HB_Fixed value)
125 {
126     return value >> 6;
127 }
128
129 // TextRunWalker walks a TextRun and presents each script run in sequence. A
130 // TextRun is a sequence of code-points with the same embedding level (i.e. they
131 // are all left-to-right or right-to-left). A script run is a subsequence where
132 // all the characters have the same script (e.g. Arabic, Thai etc). Shaping is
133 // only ever done with script runs since the shapers only know how to deal with
134 // a single script.
135 //
136 // After creating it, the script runs are either iterated backwards or forwards.
137 // It defaults to backwards for RTL and forwards otherwise (which matches the
138 // presentation order), however you can set it with |setBackwardsIteration|.
139 //
140 // Once you have setup the object, call |nextScriptRun| to get the first script
141 // run. This will return false when the iteration is complete. At any time you
142 // can call |reset| to start over again.
143 class TextRunWalker {
144 public:
145     TextRunWalker(const TextRun& run, SkPaint* paint, unsigned startingX, const FontPlatformData* font)
146         : m_run(run)
147         , m_startingX(startingX)
148         , m_offsetX(m_startingX)
149         , m_iterateBackwards(run.rtl())
150     {
151         memset(&m_item, 0, sizeof(m_item));
152         // We cannot know, ahead of time, how many glyphs a given script run
153         // will produce. We take a guess that script runs will not produce more
154         // than twice as many glyphs as there are code points and fallback if
155         // we find that we are wrong.
156         m_maxGlyphs = run.length() * 2;
157         createGlyphArrays();
158
159         m_item.log_clusters = new unsigned short[run.length()];
160
161         m_item.face = HB_NewFace(const_cast<FontPlatformData*>(font), harfbuzzSkiaGetTable);
162         m_item.font = allocHarfbuzzFont(const_cast<FontPlatformData*>(font));
163         // This sets up the SkPaint graphics context such that the text related
164         // input will always by assumed to be font specific glyph ids.
165         paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
166
167         m_item.string = run.characters();
168         m_item.stringLength = run.length();
169         m_item.item.bidiLevel = run.rtl();
170
171         reset();
172     }
173
174     ~TextRunWalker()
175     {
176         fastFree(m_item.font);
177         deleteGlyphArrays();
178         delete[] m_item.log_clusters;
179         HB_FreeFace(m_item.face);
180     }
181
182     void reset()
183     {
184         if (m_iterateBackwards)
185             m_indexOfNextScriptRun = m_run.length() - 1;
186         else
187             m_indexOfNextScriptRun = 0;
188         m_offsetX = m_startingX;
189     }
190
191     // Set the x offset for the next script run. This affects the values in
192     // |xPositions|
193     void setXOffsetToZero()
194     {
195         m_offsetX = 0;
196     }
197
198     bool rtl() const
199     {
200         return m_run.rtl();
201     }
202
203     void setBackwardsIteration(bool isBackwards)
204     {
205         m_iterateBackwards = isBackwards;
206         reset();
207     }
208
209     // Advance to the next script run, returning false when the end of the
210     // TextRun has been reached.
211     bool nextScriptRun()
212     {
213         if (m_iterateBackwards) {
214             // In right-to-left mode we need to render the shaped glyph backwards and
215             // also render the script runs themselves backwards. So given a TextRun:
216             //    AAAAAAACTTTTTTT   (A = Arabic, C = Common, T = Thai)
217             // we render:
218             //    TTTTTTCAAAAAAA
219             // (and the glyphs in each A, C and T section are backwards too)
220             if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
221                 return false;
222         } else {
223             if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
224                 return false;
225         }
226
227         if (!shapeGlyphs())
228             return false;
229         setGlyphXPositions(rtl());
230         return true;
231     }
232
233     const uint16_t* glyphs() const
234     {
235         return m_glyphs16;
236     }
237
238     // Return the length of the array returned by |glyphs|
239     const unsigned length() const
240     {
241         return m_item.num_glyphs;
242     }
243
244     // Return the x offset for each of the glyphs. Note that this is translated
245     // by the current x offset and that the x offset is updated for each script
246     // run.
247     const SkScalar* xPositions() const
248     {
249         return m_xPositions;
250     }
251
252     // Get the advances (widths) for each glyph.
253     const HB_Fixed* advances() const
254     {
255         return m_item.advances;
256     }
257
258     // Return the width (in px) of the current script run.
259     const unsigned width() const
260     {
261         return m_pixelWidth;
262     }
263
264     // Return the cluster log for the current script run. For example:
265     //   script run: f i a n c é  (fi gets ligatured)
266     //   log clutrs: 0 0 1 2 3 4
267     // So, for each input code point, the log tells you which output glyph was
268     // generated for it.
269     const unsigned short* logClusters() const
270     {
271         return m_item.log_clusters;
272     }
273
274     // return the number of code points in the current script run
275     const unsigned numCodePoints() const
276     {
277         return m_numCodePoints;
278     }
279
280
281     float widthOfFullRun()
282     {
283         float widthSum = 0;
284         while (nextScriptRun())
285             widthSum += width();
286
287         return widthSum;
288     }
289
290 private:
291     HB_FontRec* allocHarfbuzzFont(void* userData)
292     {
293         HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
294         memset(font, 0, sizeof(HB_FontRec));
295         font->klass = &harfbuzzSkiaClass;
296         font->userData = userData;
297         // The values which harfbuzzSkiaClass returns are already scaled to
298         // pixel units, so we just set all these to one to disable further
299         // scaling.
300         font->x_ppem = 1;
301         font->y_ppem = 1;
302         font->x_scale = 1;
303         font->y_scale = 1;
304
305         return font;
306     }
307
308     void deleteGlyphArrays()
309     {
310         delete[] m_item.glyphs;
311         delete[] m_item.attributes;
312         delete[] m_item.advances;
313         delete[] m_item.offsets;
314         delete[] m_glyphs16;
315         delete[] m_xPositions;
316     }
317
318     bool createGlyphArrays()
319     {
320         m_item.glyphs = new HB_Glyph[m_maxGlyphs];
321         m_item.attributes = new HB_GlyphAttributes[m_maxGlyphs];
322         m_item.advances = new HB_Fixed[m_maxGlyphs];
323         m_item.offsets = new HB_FixedPoint[m_maxGlyphs];
324         m_glyphs16 = new uint16_t[m_maxGlyphs];
325         m_xPositions = new SkScalar[m_maxGlyphs];
326
327         return m_item.glyphs
328             && m_item.attributes
329             && m_item.advances
330             && m_item.offsets
331             && m_glyphs16
332             && m_xPositions;
333     }
334
335     bool expandGlyphArrays()
336     {
337         deleteGlyphArrays();
338         m_maxGlyphs <<= 1;
339         return createGlyphArrays();
340     }
341
342     bool shapeGlyphs()
343     {
344         for (;;) {
345             m_item.num_glyphs = m_maxGlyphs;
346             HB_ShapeItem(&m_item);
347             if (m_item.num_glyphs < m_maxGlyphs)
348                 break;
349
350             // We overflowed our arrays. Resize and retry.
351             if (!expandGlyphArrays())
352                 return false;
353         }
354
355         return true;
356     }
357
358     void setGlyphXPositions(bool isRTL)
359     {
360         m_pixelWidth = 0;
361         for (unsigned i = 0; i < m_item.num_glyphs; ++i) {
362             int index;
363             if (isRTL)
364                 index = m_item.num_glyphs - (i + 1);
365             else
366                 index = i;
367
368             m_glyphs16[i] = m_item.glyphs[i];
369             m_xPositions[index] = m_offsetX + m_pixelWidth;
370             m_pixelWidth += truncateFixedPointToInteger(m_item.advances[index]);
371         }
372         m_offsetX += m_pixelWidth;
373     }
374
375     const TextRun& m_run;
376     HB_ShaperItem m_item;
377     uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
378     SkScalar* m_xPositions; // A vector of x positions for each glyph.
379     ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
380     const unsigned m_startingX; // Offset in pixels of the first script run.
381     unsigned m_offsetX; // Offset in pixels to the start of the next script run.
382     unsigned m_pixelWidth; // Width (in px) of the current script run.
383     unsigned m_numCodePoints; // Code points in current script run.
384     unsigned m_maxGlyphs; // Current size of all the Harfbuzz arrays.
385     bool m_iterateBackwards;
386 };
387
388 static void setupForTextPainting(const FontPlatformData& font, SkPaint* paint, SkColor color)
389 {
390     font.setupPaint(paint);
391     paint->setFlags(SkPaint::kAntiAlias_Flag);
392     paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
393     paint->setColor(color);
394 }
395
396 static FontPlatformData fontPlatformDataForTextRun(const Font* font, const TextRun& run)
397 {
398     return font->fontDataForCharacters(run.characters(), run.length())->fontDataForCharacter(' ')->platformData();
399 }
400
401 void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
402                            const FloatPoint& point, int from, int to) const
403 {
404     if (!run.length())
405         return;
406
407     const FontPlatformData& font = fontPlatformDataForTextRun(this, run);
408
409     SkCanvas* canvas = gc->platformContext()->canvas();
410     int textMode = gc->platformContext()->getTextDrawingMode();
411     bool fill = textMode & cTextFill;
412     bool stroke = (textMode & cTextStroke)
413                && gc->platformContext()->getStrokeStyle() != NoStroke
414                && gc->platformContext()->getStrokeThickness() > 0;
415
416     if (!fill && !stroke)
417         return;
418
419     SkPaint strokePaint, fillPaint;
420     if (fill) {
421         gc->platformContext()->setupPaintForFilling(&fillPaint);
422         setupForTextPainting(font, &fillPaint, gc->fillColor().rgb());
423     }
424     if (stroke) {
425         gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
426         setupForTextPainting(font, &strokePaint, gc->strokeColor().rgb());
427     }
428
429     TextRunWalker walker(run, stroke ? &strokePaint : &fillPaint, point.x(), &font);
430
431     while (walker.nextScriptRun()) {
432         if (fill)
433             canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint);
434         if (stroke)
435             canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint);
436     }
437 }
438
439 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const
440 {
441     SkPaint paint;
442     const FontPlatformData& font = fontPlatformDataForTextRun(this, run);
443     font.setupPaint(&paint);
444
445     TextRunWalker walker(run, &paint, 0, &font);
446     return walker.widthOfFullRun();
447 }
448
449 static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x)
450 {
451     const HB_Fixed* advances = walker.advances();
452     int glyphIndex;
453     if (walker.rtl()) {
454         for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) {
455             if (x < truncateFixedPointToInteger(advances[glyphIndex]))
456                 break;
457             x -= truncateFixedPointToInteger(advances[glyphIndex]);
458         }
459     } else {
460         for (glyphIndex = 0; glyphIndex < walker.length(); ++glyphIndex) {
461             if (x < truncateFixedPointToInteger(advances[glyphIndex]))
462                 break;
463             x -= truncateFixedPointToInteger(advances[glyphIndex]);
464         }
465     }
466
467     return glyphIndex;
468 }
469
470 // Return the code point index for the given |x| offset into the text run.
471 int Font::offsetForPositionForComplexText(const TextRun& run, int x,
472                                           bool includePartialGlyphs) const
473 {
474     // (Mac code ignores includePartialGlyphs, and they don't know what it's
475     // supposed to do, so we just ignore it as well.)
476     SkPaint paint;
477     const FontPlatformData& font = fontPlatformDataForTextRun(this, run);
478     font.setupPaint(&paint);
479
480     TextRunWalker walker(run, &paint, 0, &font);
481
482     // If this is RTL text, the first glyph from the left is actually the last
483     // code point. So we need to know how many code points there are total in
484     // order to subtract. This is different from the length of the TextRun
485     // because UTF-16 surrogate pairs are a single code point, but 32-bits long.
486     // In LTR we leave this as 0 so that we get the correct value for
487     // |basePosition|, below.
488     unsigned totalCodePoints = 0;
489     if (walker.rtl()) {
490         ssize_t offset = 0;
491         while (offset < run.length()) {
492             utf16_to_code_point(run.characters(), run.length(), &offset);
493             totalCodePoints++;
494         }
495     }
496
497     unsigned basePosition = totalCodePoints;
498
499     // For RTL:
500     //   code-point order:  abcd efg hijkl
501     //   on screen:         lkjih gfe dcba
502     //                                ^   ^
503     //                                |   |
504     //                  basePosition--|   |
505     //                 totalCodePoints----|
506     // Since basePosition is currently the total number of code-points, the
507     // first thing we do is decrement it so that it's pointing to the start of
508     // the current script-run.
509     //
510     // For LTR, basePosition is zero so it already points to the start of the
511     // first script run.
512     while (walker.nextScriptRun()) {
513         if (walker.rtl())
514             basePosition -= walker.numCodePoints();
515
516         if (x < walker.width()) {
517             // The x value in question is within this script run. We consider
518             // each glyph in presentation order and stop when we find the one
519             // covering this position.
520             const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x);
521
522             // Now that we have a glyph index, we have to turn that into a
523             // code-point index. Because of ligatures, several code-points may
524             // have gone into a single glyph. We iterate over the clusters log
525             // and find the first code-point which contributed to the glyph.
526             const unsigned short* log = walker.logClusters();
527             for (unsigned j = 0; j < walker.numCodePoints(); ++j) {
528                 if (log[j] == glyphIndex)
529                     return basePosition + j;
530             }
531
532             ASSERT_NOT_REACHED();
533         }
534
535         x -= walker.width();
536
537         if (!walker.rtl())
538             basePosition += walker.numCodePoints();
539     }
540
541     return basePosition;
542 }
543
544 // Return the rectangle for selecting the given range of code-points in the TextRun.
545 FloatRect Font::selectionRectForComplexText(const TextRun& run,
546                                             const IntPoint& point, int height,
547                                             int from, int to) const
548 {
549     SkPaint paint;
550     const FontPlatformData& font = fontPlatformDataForTextRun(this, run);
551     font.setupPaint(&paint);
552
553     int fromX = -1, toX = -1, fromAdvance = -1, toAdvance = -1;
554
555     TextRunWalker walker(run, &paint, 0, &font);
556
557     // Base will point to the x offset for the current script run. Note that, in
558     // the LTR case, width will be 0.
559     int base = walker.rtl() ? walker.widthOfFullRun() : 0;
560     const int leftEdge = base;
561
562     // We want to enumerate the script runs in code point order in the following
563     // code. This call also resets |walker|.
564     walker.setBackwardsIteration(false);
565
566     while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) {
567         // TextRunWalker will helpfully accululate the x offsets for different
568         // script runs for us. For this code, however, we always want the x offsets
569         // to start from zero so we call this before each script run.
570         walker.setXOffsetToZero();
571
572         if (walker.rtl())
573             base -= walker.width();
574
575         if (fromX == -1 && from < walker.numCodePoints()) {
576             // |from| is within this script run. So we index the clusters log to
577             // find which glyph this code-point contributed to and find its x
578             // position.
579             int glyph = walker.logClusters()[from];
580             fromX = base + walker.xPositions()[glyph];
581             fromAdvance = walker.advances()[glyph];
582         } else
583             from -= walker.numCodePoints();
584
585         if (toX == -1 && to < walker.numCodePoints()) {
586             int glyph = walker.logClusters()[to];
587             toX = base + walker.xPositions()[glyph];
588             toAdvance = walker.advances()[glyph];
589         } else
590             to -= walker.numCodePoints();
591
592         if (!walker.rtl())
593             base += walker.width();
594     }
595
596     // The position in question might be just after the text.
597     const int rightEdge = base;
598     if (fromX == -1 && !from)
599         fromX = leftEdge;
600     else if (walker.rtl())
601        fromX += truncateFixedPointToInteger(fromAdvance);
602
603     if (toX == -1 && !to)
604         toX = rightEdge;
605     else if (!walker.rtl())
606         toX += truncateFixedPointToInteger(toAdvance);
607
608     ASSERT(fromX != -1 && toX != -1);
609
610     if (fromX < toX)
611         return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
612
613     return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
614 }
615
616 } // namespace WebCore