2 * Copyright (C) 2009 Martin Hosken
3 * Copyright (C) 2009 SIL International
5 * This is part of HarfBuzz, a text shaping library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 #include <graphite/GrClient.h>
27 #include <graphite/ITextSource.h>
28 #include <graphite/GrData.h>
29 #include <graphite/GrConstants.h>
30 #include <graphite/Segment.h>
31 #include "hb-buffer-private.hh"
32 #include "hb-font-private.h"
33 #include "hb-graphite.h"
41 extern int FontAscent(const void *pOS2
);
42 extern int FontDescent(const void *pOS2
);
43 extern int DesignUnits(const void *pHead
);
44 extern bool FontOs2Style(const void *pOS2
, bool &fBold
, bool &fItalic
);
47 typedef struct _featureSetting
{
52 class HbGrBufferTextSrc
: public gr::ITextSource
55 HbGrBufferTextSrc(hb_buffer_t
*buff
, hb_feature_t
*feats
, unsigned int num_features
)
57 hb_feature_t
*aFeat
= feats
;
58 featureSetting
*aNewFeat
;
60 buffer
= hb_buffer_reference(buff
);
61 features
= new featureSetting
[num_features
];
62 nFeatures
= num_features
;
64 for (unsigned int i
= 0; i
< num_features
; i
++, aFeat
++, aNewFeat
++)
66 aNewFeat
->id
= aFeat
->tag
;
67 aNewFeat
->value
= aFeat
->value
;
70 ~HbGrBufferTextSrc() { hb_buffer_destroy(buffer
); delete[] features
; };
71 virtual gr::UtfType
utfEncodingForm() { return gr::kutf32
; };
72 virtual size_t getLength() { return buffer
->len
; };
73 virtual size_t fetch(gr::toffset ichMin
, size_t cch
, gr::utf32
* prgchBuffer
)
75 assert(cch
<= buffer
->len
);
76 if (cch
> buffer
->len
)
78 for (unsigned int i
= ichMin
; i
< ichMin
+ cch
; i
++)
79 prgchBuffer
[i
- ichMin
] = buffer
->info
[i
].codepoint
;
80 return (cch
- ichMin
);
82 virtual size_t fetch(gr::toffset ichMin
, size_t cch
, gr::utf16
* prgchBuffer
) { return 0 ;};
83 virtual size_t fetch(gr::toffset ichMin
, size_t cch
, gr::utf8
* prgchBuffer
) { return 0; };
84 virtual bool getRightToLeft(gr::toffset ich
)
85 { return hb_buffer_get_direction(buffer
) == HB_DIRECTION_RTL
; };
86 virtual unsigned int getDirectionDepth(gr::toffset ich
)
87 { return hb_buffer_get_direction(buffer
) == HB_DIRECTION_RTL
? 1 : 0; };
88 virtual float getVerticalOffset(gr::toffset ich
) { return 0; };
89 virtual gr::isocode
getLanguage(gr::toffset ich
)
92 char *p
= (char *)(buffer
->language
);
94 for (i
= 0; i
< 4; i
++)
106 virtual std::pair
<gr::toffset
, gr::toffset
> propertyRange(gr::toffset ich
)
107 { return std::pair
<gr::toffset
, gr::toffset
>(0, buffer
->len
); };
108 virtual size_t getFontFeatures(gr::toffset ich
, gr::FeatureSetting
* prgfset
)
110 featureSetting
*aFeat
= features
;
111 for (unsigned int i
= 0; i
< nFeatures
; i
++, aFeat
++, prgfset
++)
113 prgfset
->id
= aFeat
->id
;
114 prgfset
->value
= aFeat
->value
;
118 virtual bool sameSegment(gr::toffset ich1
, gr::toffset ich2
) {return true; };
122 featureSetting
*features
;
123 unsigned int nFeatures
;
126 class HbGrFont
: public gr::Font
129 HbGrFont(hb_font_t
*font
, hb_face_t
*face
) : gr::Font()
130 { m_font
= hb_font_reference(font
); m_face
= hb_face_reference(face
); initfont(); };
133 std::map
<hb_tag_t
,hb_blob_t
*>::iterator p
= m_blobs
.begin();
134 while (p
!= m_blobs
.end())
135 { hb_blob_destroy((p
++)->second
); }
136 hb_font_destroy(m_font
);
137 hb_face_destroy(m_face
);
139 HbGrFont (const HbGrFont
&font
) : gr::Font(font
)
142 m_blobs
= std::map
<hb_tag_t
, hb_blob_t
*>(font
.m_blobs
);
143 std::map
<hb_tag_t
,hb_blob_t
*>::iterator p
=m_blobs
.begin();
144 while (p
!= m_blobs
.end()) { hb_blob_reference((*p
++).second
); }
145 hb_font_reference(m_font
);
146 hb_face_reference(m_face
);
148 virtual HbGrFont
*copyThis() { return new HbGrFont(*this); };
149 virtual bool bold() { return m_bold
; };
150 virtual bool italic() { return m_italic
; };
151 virtual float ascent() { float asc
; getFontMetrics(&asc
, NULL
, NULL
); return asc
; };
152 virtual float descent() { float desc
; getFontMetrics(NULL
, &desc
, NULL
); return desc
; };
153 virtual float height()
154 { float asc
, desc
; getFontMetrics(&asc
, &desc
, NULL
); return (asc
+ desc
); };
155 virtual unsigned int getDPIx() { return m_font
->x_ppem
; };
156 virtual unsigned int getDPIy() { return m_font
->y_ppem
; };
157 virtual const void *getTable(gr::fontTableId32 tableID
, size_t *pcbsize
)
160 std::map
<hb_tag_t
,hb_blob_t
*>::iterator p
=m_blobs
.find((hb_tag_t
)tableID
);
161 if (p
== m_blobs
.end())
163 blob
= hb_face_get_table(m_face
, (hb_tag_t
)tableID
);
164 m_blobs
[(hb_tag_t
)tableID
] = blob
;
167 { blob
= p
->second
; }
169 const char *res
= hb_blob_lock(blob
);
171 *pcbsize
= hb_blob_get_length(blob
);
172 hb_blob_unlock(blob
);
173 return (const void *)res
;
176 virtual void getFontMetrics(float *pAscent
, float *pDescent
, float *pEmSquare
)
178 if (pAscent
) *pAscent
= 1. * m_ascent
* m_font
->y_ppem
/ m_emsquare
;
179 if (pDescent
) *pDescent
= 1. * m_descent
* m_font
->y_ppem
/ m_emsquare
;
180 if (pEmSquare
) *pEmSquare
= m_font
->x_scale
;
182 virtual void getGlyphPoint(gr::gid16 glyphID
, unsigned int pointNum
, gr::Point
&pointReturn
)
185 hb_font_get_contour_point(m_font
, m_face
, pointNum
, glyphID
, &x
, &y
);
186 pointReturn
.x
= (float)x
;
187 pointReturn
.y
= (float)y
;
190 virtual void getGlyphMetrics(gr::gid16 glyphID
, gr::Rect
&boundingBox
, gr::Point
&advances
)
192 hb_glyph_metrics_t metrics
;
193 hb_font_get_glyph_metrics(m_font
, m_face
, glyphID
, &metrics
);
194 boundingBox
.top
= (metrics
.y_offset
+ metrics
.height
);
195 boundingBox
.bottom
= metrics
.y_offset
;
196 boundingBox
.left
= metrics
.x_offset
;
197 boundingBox
.right
= (metrics
.x_offset
+ metrics
.width
);
198 advances
.x
= metrics
.x_advance
;
199 advances
.y
= metrics
.y_advance
;
200 // fprintf (stderr, "%d: (%d, %d, %d, %d)+(%d, %d)\n", glyphID, metrics.x_offset, metrics.y_offset, metrics.width, metrics.height, metrics.x_advance, metrics.y_advance);
204 HB_INTERNAL
void initfont();
213 std::map
<hb_tag_t
, hb_blob_t
*> m_blobs
;
216 void HbGrFont::initfont()
218 const void *pOS2
= getTable(gr::kttiOs2
, NULL
);
219 const void *pHead
= getTable(gr::kttiHead
, NULL
);
220 TtfUtil::FontOs2Style(pOS2
, m_bold
, m_italic
);
221 m_ascent
= static_cast<float>(TtfUtil::FontAscent(pOS2
));
222 m_descent
= static_cast<float>(TtfUtil::FontDescent(pOS2
));
223 m_emsquare
= static_cast<float>(TtfUtil::DesignUnits(pHead
));
227 hb_graphite_shape (hb_font_t
*font
,
230 hb_feature_t
*features
,
231 unsigned int num_features
)
233 /* create text source */
234 HbGrBufferTextSrc
textSrc(buffer
, features
, num_features
);
237 HbGrFont
grfont(font
, face
);
244 gr::LayoutEnvironment layout
;
245 std::pair
<gr::GlyphIterator
, gr::GlyphIterator
>glyph_range
;
246 gr::GlyphIterator iGlyph
;
247 hb_codepoint_t
*glyph_infos
, *pGlyph
;
248 hb_glyph_position_t
*pPosition
;
252 layout
.setStartOfLine(0);
253 layout
.setEndOfLine(0);
254 layout
.setDumbFallback(true);
255 layout
.setJustifier(NULL
);
256 layout
.setRightToLeft(false);
258 gr::RangeSegment
pSegment(&grfont
, &textSrc
, &layout
, (gr::toffset
)0,
259 static_cast<gr::toffset
>(buffer
->len
), (gr::Segment
*)NULL
);
261 /* fill in buffer from segment */
262 _hb_buffer_clear_output(buffer
);
263 pSegment
.getUniscribeClusters(NULL
, 0, &numChars
, NULL
, 0, &numGlyphs
);
264 firsts
= new int[numChars
];
265 flags
= new bool[numGlyphs
];
266 glyph_infos
= new hb_codepoint_t
[numGlyphs
];
267 hb_buffer_ensure(buffer
, numGlyphs
);
268 pSegment
.getUniscribeClusters(firsts
, numChars
, NULL
, flags
, numGlyphs
, NULL
);
269 glyph_range
= pSegment
.glyphs();
270 for (pGlyph
= glyph_infos
, iGlyph
= glyph_range
.first
; iGlyph
!= glyph_range
.second
;
272 { *pGlyph
= iGlyph
->glyphID(); }
274 while (cGlyph
< numGlyphs
)
278 int oldcChar
= cChar
++;
279 int oldcGlyph
= cGlyph
++;
280 while (cChar
< numChars
&& firsts
[cChar
] == firsts
[oldcChar
]) cChar
++;
281 while (cGlyph
< numGlyphs
&& !flags
[cGlyph
]) cGlyph
++;
282 _hb_buffer_add_output_glyphs(buffer
, cChar
- oldcChar
, cGlyph
- oldcGlyph
,
283 glyph_infos
+ oldcGlyph
, 0xFFFF, 0xFFFF);
286 { cGlyph
++; } /* This should never happen */
289 float curradvx
= 0., curradvy
= 0.;
290 for (pPosition
= hb_buffer_get_glyph_positions(buffer
), iGlyph
= glyph_range
.first
;
291 iGlyph
!= glyph_range
.second
; pPosition
++, iGlyph
++)
293 pPosition
->x_offset
= iGlyph
->origin() - curradvx
;
294 pPosition
->y_offset
= iGlyph
->yOffset() - curradvy
;
295 pPosition
->x_advance
= pPosition
->x_offset
+ iGlyph
->advanceWidth();
296 pPosition
->y_advance
= pPosition
->y_offset
+ iGlyph
->advanceHeight();
297 if (pPosition
->x_advance
< 0 && iGlyph
->logicalIndex() != iGlyph
->attachedClusterBase()->logicalIndex())
298 pPosition
->x_advance
= 0;
299 curradvx
+= pPosition
->x_advance
;
300 curradvy
+= pPosition
->y_advance
;
301 // fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
304 delete[] glyph_infos
;