27 #include "jni_util.h" |
27 #include "jni_util.h" |
28 #include "jlong.h" |
28 #include "jlong.h" |
29 #include "sunfontids.h" |
29 #include "sunfontids.h" |
30 #include "sun_font_FreetypeFontScaler.h" |
30 #include "sun_font_FreetypeFontScaler.h" |
31 |
31 |
32 #include<stdlib.h> |
32 #include <stdlib.h> |
|
33 #if !defined(_WIN32) && !defined(__APPLE_) |
|
34 #include <dlfcn.h> |
|
35 #endif |
33 #include <math.h> |
36 #include <math.h> |
34 #include "ft2build.h" |
37 #include "ft2build.h" |
35 #include FT_FREETYPE_H |
38 #include FT_FREETYPE_H |
36 #include FT_GLYPH_H |
39 #include FT_GLYPH_H |
37 #include FT_BBOX_H |
40 #include FT_BBOX_H |
38 #include FT_SIZES_H |
41 #include FT_SIZES_H |
39 #include FT_OUTLINE_H |
42 #include FT_OUTLINE_H |
40 #include FT_SYNTHESIS_H |
43 #include FT_SYNTHESIS_H |
41 #include FT_LCD_FILTER_H |
44 #include FT_LCD_FILTER_H |
|
45 #include FT_MODULE_H |
42 |
46 |
43 #include "fontscaler.h" |
47 #include "fontscaler.h" |
44 |
48 |
45 #define ftFixed1 (FT_Fixed) (1 << 16) |
49 #define ftFixed1 (FT_Fixed) (1 << 16) |
46 #define FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1)) |
50 #define FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1)) |
148 FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer; |
152 FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer; |
149 JNIEnv* env = scalerInfo->env; |
153 JNIEnv* env = scalerInfo->env; |
150 jobject bBuffer; |
154 jobject bBuffer; |
151 int bread = 0; |
155 int bread = 0; |
152 |
156 |
153 if (numBytes == 0) return 0; |
157 /* A call with numBytes == 0 is a seek. It should return 0 if the |
|
158 * seek position is within the file and non-zero otherwise. |
|
159 * For all other cases, ie numBytes !=0, return the number of bytes |
|
160 * actually read. This applies to truncated reads and also failed reads. |
|
161 */ |
|
162 |
|
163 if (numBytes == 0) { |
|
164 if (offset > scalerInfo->fileSize) { |
|
165 return -1; |
|
166 } else { |
|
167 return 0; |
|
168 } |
|
169 } |
|
170 |
|
171 if (offset + numBytes < offset) { |
|
172 return 0; // ft should not do this, but just in case. |
|
173 } |
|
174 |
|
175 if (offset >= scalerInfo->fileSize) { |
|
176 return 0; |
|
177 } |
|
178 |
|
179 if (offset + numBytes > scalerInfo->fileSize) { |
|
180 numBytes = scalerInfo->fileSize - offset; |
|
181 } |
154 |
182 |
155 /* Large reads will bypass the cache and data copying */ |
183 /* Large reads will bypass the cache and data copying */ |
156 if (numBytes > FILEDATACACHESIZE) { |
184 if (numBytes > FILEDATACACHESIZE) { |
157 bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes); |
185 bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes); |
158 if (bBuffer != NULL) { |
186 if (bBuffer != NULL) { |
159 bread = (*env)->CallIntMethod(env, |
187 bread = (*env)->CallIntMethod(env, |
160 scalerInfo->font2D, |
188 scalerInfo->font2D, |
161 sunFontIDs.ttReadBlockMID, |
189 sunFontIDs.ttReadBlockMID, |
162 bBuffer, offset, numBytes); |
190 bBuffer, offset, numBytes); |
163 return bread; |
191 if (bread < 0) { |
|
192 return 0; |
|
193 } else { |
|
194 return bread; |
|
195 } |
164 } else { |
196 } else { |
165 /* We probably hit bug 4845371. For reasons that |
197 /* We probably hit bug 4845371. For reasons that |
166 * are currently unclear, the call stacks after the initial |
198 * are currently unclear, the call stacks after the initial |
167 * createScaler call that read large amounts of data seem to |
199 * createScaler call that read large amounts of data seem to |
168 * be OK and can create the byte buffer above, but this code |
200 * be OK and can create the byte buffer above, but this code |
173 */ |
205 */ |
174 jbyteArray byteArray = (jbyteArray) |
206 jbyteArray byteArray = (jbyteArray) |
175 (*env)->CallObjectMethod(env, scalerInfo->font2D, |
207 (*env)->CallObjectMethod(env, scalerInfo->font2D, |
176 sunFontIDs.ttReadBytesMID, |
208 sunFontIDs.ttReadBytesMID, |
177 offset, numBytes); |
209 offset, numBytes); |
178 (*env)->GetByteArrayRegion(env, byteArray, |
210 /* If there's an OutofMemoryError then byteArray will be null */ |
179 0, numBytes, (jbyte*)destBuffer); |
211 if (byteArray == NULL) { |
180 return numBytes; |
212 return 0; |
|
213 } else { |
|
214 jsize len = (*env)->GetArrayLength(env, byteArray); |
|
215 if (len < numBytes) { |
|
216 numBytes = len; // don't get more bytes than there are .. |
|
217 } |
|
218 (*env)->GetByteArrayRegion(env, byteArray, |
|
219 0, numBytes, (jbyte*)destBuffer); |
|
220 return numBytes; |
|
221 } |
181 } |
222 } |
182 } /* Do we have a cache hit? */ |
223 } /* Do we have a cache hit? */ |
183 else if (scalerInfo->fontDataOffset <= offset && |
224 else if (scalerInfo->fontDataOffset <= offset && |
184 scalerInfo->fontDataOffset + scalerInfo->fontDataLength >= |
225 scalerInfo->fontDataOffset + scalerInfo->fontDataLength >= |
185 offset + numBytes) |
226 offset + numBytes) |
197 bBuffer = scalerInfo->directBuffer; |
238 bBuffer = scalerInfo->directBuffer; |
198 bread = (*env)->CallIntMethod(env, scalerInfo->font2D, |
239 bread = (*env)->CallIntMethod(env, scalerInfo->font2D, |
199 sunFontIDs.ttReadBlockMID, |
240 sunFontIDs.ttReadBlockMID, |
200 bBuffer, offset, |
241 bBuffer, offset, |
201 scalerInfo->fontDataLength); |
242 scalerInfo->fontDataLength); |
|
243 if (bread <= 0) { |
|
244 return 0; |
|
245 } else if (bread < numBytes) { |
|
246 numBytes = bread; |
|
247 } |
202 memcpy(destBuffer, scalerInfo->fontData, numBytes); |
248 memcpy(destBuffer, scalerInfo->fontData, numBytes); |
203 return numBytes; |
249 return numBytes; |
204 } |
250 } |
|
251 } |
|
252 |
|
253 typedef FT_Error (*FT_Prop_Set_Func)(FT_Library library, |
|
254 const FT_String* module_name, |
|
255 const FT_String* property_name, |
|
256 const void* value ); |
|
257 |
|
258 /** |
|
259 * Prefer the older v35 freetype byte code interpreter. |
|
260 */ |
|
261 static void setInterpreterVersion(FT_Library library) { |
|
262 |
|
263 char* props = getenv("FREETYPE_PROPERTIES"); |
|
264 int version = 35; |
|
265 const char* module = "truetype"; |
|
266 const char* property = "interpreter-version"; |
|
267 |
|
268 /* If some one is setting this, don't override it */ |
|
269 if (props != NULL && strstr(property, props)) { |
|
270 return; |
|
271 } |
|
272 /* |
|
273 * FT_Property_Set was introduced in 2.4.11. |
|
274 * Some older supported Linux OSes may not include it so look |
|
275 * this up dynamically. |
|
276 * And if its not available it doesn't matter, since the reason |
|
277 * we need it dates from 2.7. |
|
278 * On Windows & Mac the library is always bundled so it is safe |
|
279 * to use directly in those cases. |
|
280 */ |
|
281 #if defined(_WIN32) || defined(__APPLE__) |
|
282 FT_Property_Set(library, module, property, (void*)(&version)); |
|
283 #else |
|
284 void *lib = dlopen("libfreetype.so", RTLD_LOCAL|RTLD_LAZY); |
|
285 if (lib == NULL) { |
|
286 lib = dlopen("libfreetype.so.6", RTLD_LOCAL|RTLD_LAZY); |
|
287 if (lib == NULL) { |
|
288 return; |
|
289 } |
|
290 } |
|
291 FT_Prop_Set_Func func = (FT_Prop_Set_Func)dlsym(lib, "FT_Property_Set"); |
|
292 if (func != NULL) { |
|
293 func(library, module, property, (void*)(&version)); |
|
294 } |
|
295 dlclose(lib); |
|
296 #endif |
205 } |
297 } |
206 |
298 |
207 /* |
299 /* |
208 * Class: sun_font_FreetypeFontScaler |
300 * Class: sun_font_FreetypeFontScaler |
209 * Method: initNativeScaler |
301 * Method: initNativeScaler |
540 |
633 |
541 NB: investigate performance benefits of refactoring code |
634 NB: investigate performance benefits of refactoring code |
542 to avoid unnecesary work with bitmaps. */ |
635 to avoid unnecesary work with bitmaps. */ |
543 |
636 |
544 GlyphInfo *info; |
637 GlyphInfo *info; |
545 jfloat advance; |
638 jfloat advance = 0.0f; |
546 jlong image; |
639 jlong image; |
547 |
640 |
548 image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative( |
641 image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative( |
549 env, scaler, font2D, pScalerContext, pScaler, glyphCode); |
642 env, scaler, font2D, pScalerContext, pScaler, glyphCode); |
550 info = (GlyphInfo*) jlong_to_ptr(image); |
643 info = (GlyphInfo*) jlong_to_ptr(image); |
551 |
644 |
552 advance = info->advanceX; |
645 if (info != NULL) { |
553 |
646 advance = info->advanceX; |
554 free(info); |
647 free(info); |
|
648 } |
555 |
649 |
556 return advance; |
650 return advance; |
557 } |
651 } |
558 |
652 |
559 /* |
653 /* |
686 dstRow += dstRowBytes; |
780 dstRow += dstRowBytes; |
687 height -= 3; |
781 height -= 3; |
688 } |
782 } |
689 } |
783 } |
690 |
784 |
|
785 |
|
786 /* JDK does not use glyph images for fonts with a |
|
787 * pixel size > 100 (see THRESHOLD in OutlineTextRenderer.java) |
|
788 * so if the glyph bitmap image dimension is > 1024 pixels, |
|
789 * something is up. |
|
790 */ |
|
791 #define MAX_GLYPH_DIM 1024 |
691 |
792 |
692 /* |
793 /* |
693 * Class: sun_font_FreetypeFontScaler |
794 * Class: sun_font_FreetypeFontScaler |
694 * Method: getGlyphImageNative |
795 * Method: getGlyphImageNative |
695 * Signature: (Lsun/font/Font2D;JI)J |
796 * Signature: (Lsun/font/Font2D;JI)J |
760 } |
861 } |
761 |
862 |
762 /* generate bitmap if it is not done yet |
863 /* generate bitmap if it is not done yet |
763 e.g. if algorithmic styling is performed and style was added to outline */ |
864 e.g. if algorithmic styling is performed and style was added to outline */ |
764 if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) { |
865 if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) { |
|
866 FT_BBox bbox; |
|
867 FT_Outline_Get_CBox(&(ftglyph->outline), &bbox); |
|
868 int w = (int)((bbox.xMax>>6)-(bbox.xMin>>6)); |
|
869 int h = (int)((bbox.yMax>>6)-(bbox.yMin>>6)); |
|
870 if (w > MAX_GLYPH_DIM || h > MAX_GLYPH_DIM) { |
|
871 glyphInfo = getNullGlyphImage(); |
|
872 return ptr_to_jlong(glyphInfo); |
|
873 } |
765 error = FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target)); |
874 error = FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target)); |
766 if (error != 0) { |
875 if (error != 0) { |
767 return ptr_to_jlong(getNullGlyphImage()); |
876 return ptr_to_jlong(getNullGlyphImage()); |
768 } |
877 } |
769 } |
878 } |
770 |
879 |
771 width = (UInt16) ftglyph->bitmap.width; |
880 width = (UInt16) ftglyph->bitmap.width; |
772 height = (UInt16) ftglyph->bitmap.rows; |
881 height = (UInt16) ftglyph->bitmap.rows; |
|
882 if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) { |
|
883 glyphInfo = getNullGlyphImage(); |
|
884 return ptr_to_jlong(glyphInfo); |
|
885 } |
|
886 |
773 |
887 |
774 imageSize = width*height; |
888 imageSize = width*height; |
775 glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize); |
889 glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize); |
776 if (glyphInfo == NULL) { |
890 if (glyphInfo == NULL) { |
777 glyphInfo = getNullGlyphImage(); |
891 glyphInfo = getNullGlyphImage(); |