1 /*
2  * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "jni.h"
27 #include "jni_util.h"
28 #include "jlong.h"
29 #include "sunfontids.h"
30 #include "sun_font_FreetypeFontScaler.h"
31 
32 #include <stdlib.h>
33 #if !defined(_WIN32) && !defined(__APPLE_)
34 #include <dlfcn.h>
35 #endif
36 #include <math.h>
37 #include "ft2build.h"
38 #include FT_FREETYPE_H
39 #include FT_GLYPH_H
40 #include FT_BBOX_H
41 #include FT_SIZES_H
42 #include FT_OUTLINE_H
43 #include FT_SYNTHESIS_H
44 #include FT_LCD_FILTER_H
45 #include FT_MODULE_H
46 #include <fontconfig/fontconfig.h>
47 
48 #include "fontscaler.h"
49 
50 #define  ftFixed1  (FT_Fixed) (1 << 16)
51 #define  FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1))
52 #define  FTFixedToFloat(x) ((x) / (float)(ftFixed1))
53 #define  FT26Dot6ToFloat(x)  ((x) / ((float) (1<<6)))
54 
55 typedef struct {
56     /* Important note:
57          JNI forbids sharing same env between different threads.
58          We are safe, because pointer is overwritten every time we get into
59          JNI call (see setupFTContext).
60 
61          Pointer is used by font data reading callbacks
62          such as ReadTTFontFileFunc.
63 
64          NB: We may consider switching to JNI_GetEnv. */
65     JNIEnv* env;
66     FT_Library library;
67     FT_Face face;
68     FT_Stream faceStream;
69     jobject font2D;
70     jobject directBuffer;
71 
72     unsigned char* fontData;
73     unsigned fontDataOffset;
74     unsigned fontDataLength;
75     unsigned fileSize;
76 } FTScalerInfo;
77 
78 typedef struct FTScalerContext {
79     FT_Matrix  transform;     /* glyph transform, including device transform */
80     jboolean   useSbits;      /* sbit usage enabled? */
81     jint       aaType;        /* antialiasing mode (off/on/grey/lcd) */
82     jint       fmType;        /* fractional metrics - on/off */
83     jboolean   doBold;        /* perform algorithmic bolding? */
84     jboolean   doItalize;     /* perform algorithmic italicizing? */
85     int        renderFlags;   /* configuration specific to particular engine */
86     int        pathType;
87     int        ptsz;          /* size in points */
88 } FTScalerContext;
89 
90 typedef struct {
91     FT_Render_Mode ftRenderMode;
92     int ftLoadFlags;
93     FT_LcdFilter ftLcdFilter;
94 } RenderingProperties;
95 
matchedPattern(const FcChar8 * family,double ptSize)96 static FcPattern* matchedPattern(const FcChar8* family, double ptSize) {
97     FcPattern* pattern = FcPatternCreate();
98     if (!pattern)
99         return 0;
100 
101     FcPatternAddString(pattern, FC_FAMILY, family);
102     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
103     FcPatternAddDouble(pattern, FC_SIZE, ptSize);
104 
105     FcConfigSubstitute(0, pattern, FcMatchPattern);
106     FcDefaultSubstitute(pattern);
107 
108     FcResult res;
109     FcPattern *match = FcFontMatch(0, pattern, &res);
110     FcPatternDestroy(pattern);
111     return (res == FcResultMatch) ? match : NULL;
112 }
113 
readFontconfig(const FcChar8 * family,double ptSize,jint aaType,RenderingProperties * rp)114 static void readFontconfig(const FcChar8* family, double ptSize, jint aaType, RenderingProperties* rp) {
115     FcPattern *pattern = matchedPattern(family, ptSize);
116 
117     FT_Render_Mode ftRenderMode = FT_RENDER_MODE_NORMAL;
118     int ftLoadFlags = FT_LOAD_DEFAULT;
119     FT_LcdFilter ftLcdFilter = FT_LCD_FILTER_DEFAULT;
120     FcBool fcAntialias = 0;
121     char horizontal = 1;
122 
123     // subpixel order
124     if (aaType == TEXT_AA_ON)
125         ftRenderMode = FT_RENDER_MODE_NORMAL;
126     else if (aaType == TEXT_AA_OFF)
127         ftRenderMode = FT_RENDER_MODE_MONO;
128     else {
129         int fcRGBA = FC_RGBA_UNKNOWN;
130         if (pattern)
131             FcPatternGetInteger(pattern, FC_RGBA, 0, &fcRGBA);
132         switch (fcRGBA) {
133         case FC_RGBA_NONE:
134             ftRenderMode = FT_RENDER_MODE_NORMAL;
135             break;
136         case FC_RGBA_RGB:
137         case FC_RGBA_BGR:
138             ftRenderMode = FT_RENDER_MODE_LCD;
139             horizontal = 1;
140             break;
141         case FC_RGBA_VRGB:
142         case FC_RGBA_VBGR:
143             ftRenderMode = FT_RENDER_MODE_LCD_V;
144             horizontal = 0;
145             break;
146         default:
147             ftRenderMode = FT_RENDER_MODE_NORMAL;
148             break;
149         }
150     }
151 
152     // loading mode
153     if (aaType == TEXT_AA_OFF)
154         ftLoadFlags |= FT_LOAD_TARGET_MONO;
155     else {
156         int fcHintStyle = FC_HINT_NONE;
157         if (pattern)
158             FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &fcHintStyle);
159         switch (fcHintStyle) {
160         case FC_HINT_NONE:
161             ftLoadFlags |= FT_LOAD_NO_HINTING;
162             break;
163         case FC_HINT_SLIGHT:
164             ftLoadFlags |= FT_LOAD_TARGET_LIGHT;
165             break;
166         case FC_HINT_MEDIUM:
167             ftLoadFlags |= FT_LOAD_TARGET_NORMAL;
168             break;
169         case FC_HINT_FULL:
170             if (aaType == TEXT_AA_ON)
171                 ftLoadFlags |= FT_LOAD_TARGET_NORMAL;
172             else
173                 ftLoadFlags |= horizontal ? FT_LOAD_TARGET_LCD : FT_LOAD_TARGET_LCD_V;
174             break;
175         default:
176             ftLoadFlags |= FT_LOAD_TARGET_NORMAL;
177             break;
178         }
179     }
180 
181     // autohinting
182     FcBool fcAutohint = 0;
183     if (pattern && FcPatternGetBool(pattern, FC_AUTOHINT, 0, &fcAutohint) == FcResultMatch)
184         if (fcAutohint)
185             ftLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
186 
187     // LCD filter
188     int fcLCDFilter = FC_LCD_DEFAULT;
189     if (pattern)
190         FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &fcLCDFilter);
191     switch (fcLCDFilter) {
192     case FC_LCD_NONE:
193         ftLcdFilter = FT_LCD_FILTER_NONE;
194         break;
195     case FC_LCD_DEFAULT:
196         ftLcdFilter = FT_LCD_FILTER_DEFAULT;
197         break;
198     case FC_LCD_LIGHT:
199         ftLcdFilter = FT_LCD_FILTER_LIGHT;
200         break;
201     case FC_LCD_LEGACY:
202         ftLcdFilter = FT_LCD_FILTER_LEGACY;
203         break;
204     default:
205         ftLcdFilter = FT_LCD_FILTER_DEFAULT;
206         break;
207     }
208 
209     if (pattern)
210         FcPatternDestroy(pattern);
211 
212     rp->ftRenderMode = ftRenderMode;
213     rp->ftLoadFlags = ftLoadFlags;
214     rp->ftLcdFilter = ftLcdFilter;
215 }
216 
217 #ifdef DEBUG
218 /* These are referenced in the freetype sources if DEBUG macro is defined.
219    To simplify work with debuging version of freetype we define
220    them here. */
221 int z_verbose;
z_error(char * s)222 void z_error(char *s) {}
223 #endif
224 
225 /**************** Error handling utilities *****************/
226 
227 static jmethodID invalidateScalerMID;
228 
229 JNIEXPORT void JNICALL
Java_sun_font_FreetypeFontScaler_initIDs(JNIEnv * env,jobject scaler,jclass FFSClass)230 Java_sun_font_FreetypeFontScaler_initIDs(
231         JNIEnv *env, jobject scaler, jclass FFSClass) {
232     invalidateScalerMID =
233         (*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V");
234 }
235 
freeNativeResources(JNIEnv * env,FTScalerInfo * scalerInfo)236 static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
237 
238     if (scalerInfo == NULL)
239         return;
240 
241     // FT_Done_Face always closes the stream, but only frees the memory
242     // of the data structure if it was internally allocated by FT.
243     // We hold on to a pointer to the stream structure if we provide it
244     // ourselves, so that we can free it here.
245     FT_Done_Face(scalerInfo->face);
246     FT_Done_FreeType(scalerInfo->library);
247 
248     if (scalerInfo->directBuffer != NULL) {
249         (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
250     }
251 
252     if (scalerInfo->fontData != NULL) {
253         free(scalerInfo->fontData);
254     }
255 
256     if (scalerInfo->faceStream != NULL) {
257         free(scalerInfo->faceStream);
258     }
259     free(scalerInfo);
260 }
261 
262 /* invalidates state of java scaler object */
invalidateJavaScaler(JNIEnv * env,jobject scaler,FTScalerInfo * scalerInfo)263 static void invalidateJavaScaler(JNIEnv *env,
264                                  jobject scaler,
265                                  FTScalerInfo* scalerInfo) {
266     freeNativeResources(env, scalerInfo);
267     (*env)->CallVoidMethod(env, scaler, invalidateScalerMID);
268 }
269 
270 /******************* I/O handlers ***************************/
271 
272 #define FILEDATACACHESIZE 1024
273 
ReadTTFontFileFunc(FT_Stream stream,unsigned long offset,unsigned char * destBuffer,unsigned long numBytes)274 static unsigned long ReadTTFontFileFunc(FT_Stream stream,
275                                         unsigned long offset,
276                                         unsigned char* destBuffer,
277                                         unsigned long numBytes)
278 {
279     FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
280     JNIEnv* env = scalerInfo->env;
281     jobject bBuffer;
282     int bread = 0;
283 
284     /* A call with numBytes == 0 is a seek. It should return 0 if the
285      * seek position is within the file and non-zero otherwise.
286      * For all other cases, ie numBytes !=0, return the number of bytes
287      * actually read. This applies to truncated reads and also failed reads.
288      */
289 
290     if (numBytes == 0) {
291         if (offset > scalerInfo->fileSize) {
292             return -1;
293         } else {
294             return 0;
295        }
296     }
297 
298     if (offset + numBytes < offset) {
299         return 0; // ft should not do this, but just in case.
300     }
301 
302     if (offset >= scalerInfo->fileSize) {
303         return 0;
304     }
305 
306     if (offset + numBytes > scalerInfo->fileSize) {
307         numBytes = scalerInfo->fileSize - offset;
308     }
309 
310     /* Large reads will bypass the cache and data copying */
311     if (numBytes > FILEDATACACHESIZE) {
312         bBuffer = (*env)->NewDirectByteBuffer(env, destBuffer, numBytes);
313         if (bBuffer != NULL) {
314             bread = (*env)->CallIntMethod(env,
315                                           scalerInfo->font2D,
316                                           sunFontIDs.ttReadBlockMID,
317                                           bBuffer, offset, numBytes);
318             if (bread < 0) {
319                 return 0;
320             } else {
321                return bread;
322             }
323         } else {
324             /* We probably hit bug 4845371. For reasons that
325              * are currently unclear, the call stacks after the initial
326              * createScaler call that read large amounts of data seem to
327              * be OK and can create the byte buffer above, but this code
328              * is here just in case.
329              * 4845371 is fixed now so I don't expect this code path to
330              * ever get called but its harmless to leave it here on the
331              * small chance its needed.
332              */
333             jbyteArray byteArray = (jbyteArray)
334             (*env)->CallObjectMethod(env, scalerInfo->font2D,
335                                      sunFontIDs.ttReadBytesMID,
336                                      offset, numBytes);
337             /* If there's an OutofMemoryError then byteArray will be null */
338             if (byteArray == NULL) {
339                 return 0;
340             } else {
341                 unsigned long len = (*env)->GetArrayLength(env, byteArray);
342                 if (len < numBytes) {
343                     numBytes = len; // don't get more bytes than there are ..
344                 }
345                 (*env)->GetByteArrayRegion(env, byteArray,
346                                            0, numBytes, (jbyte*)destBuffer);
347                 return numBytes;
348             }
349         }
350     } /* Do we have a cache hit? */
351       else if (scalerInfo->fontDataOffset <= offset &&
352         scalerInfo->fontDataOffset + scalerInfo->fontDataLength >=
353                                                          offset + numBytes)
354     {
355         unsigned cacheOffset = offset - scalerInfo->fontDataOffset;
356 
357         memcpy(destBuffer, scalerInfo->fontData+(size_t)cacheOffset, numBytes);
358         return numBytes;
359     } else {
360         /* Must fill the cache */
361         scalerInfo->fontDataOffset = offset;
362         scalerInfo->fontDataLength =
363                  (offset + FILEDATACACHESIZE > scalerInfo->fileSize) ?
364                  scalerInfo->fileSize - offset : FILEDATACACHESIZE;
365         bBuffer = scalerInfo->directBuffer;
366         bread = (*env)->CallIntMethod(env, scalerInfo->font2D,
367                                       sunFontIDs.ttReadBlockMID,
368                                       bBuffer, offset,
369                                       scalerInfo->fontDataLength);
370         if (bread <= 0) {
371             return 0;
372         } else if ((unsigned long)bread < numBytes) {
373            numBytes = bread;
374         }
375         memcpy(destBuffer, scalerInfo->fontData, numBytes);
376         return numBytes;
377     }
378 }
379 
380 typedef FT_Error (*FT_Prop_Set_Func)(FT_Library library,
381                                      const FT_String*  module_name,
382                                      const FT_String*  property_name,
383                                      const void*       value );
384 
385 /**
386  * Prefer the older v35 freetype byte code interpreter.
387  */
setInterpreterVersion(FT_Library library)388 static void setInterpreterVersion(FT_Library library) {
389 
390     char* props = getenv("FREETYPE_PROPERTIES");
391     int version = 35;
392     const char* module = "truetype";
393     const char* property = "interpreter-version";
394 
395     /* If some one is setting this, don't override it */
396     if (props != NULL && strstr(props, property)) {
397         return;
398     }
399     /*
400      * FT_Property_Set was introduced in 2.4.11.
401      * Some older supported Linux OSes may not include it so look
402      * this up dynamically.
403      * And if its not available it doesn't matter, since the reason
404      * we need it dates from 2.7.
405      * On Windows & Mac the library is always bundled so it is safe
406      * to use directly in those cases.
407      */
408 #if defined(_WIN32) || defined(__APPLE__)
409     FT_Property_Set(library, module, property, (void*)(&version));
410 #else
411     void *lib = dlopen("libfreetype.so", RTLD_LOCAL|RTLD_LAZY);
412     if (lib == NULL) {
413         lib = dlopen("libfreetype.so.6", RTLD_LOCAL|RTLD_LAZY);
414         if (lib == NULL) {
415             return;
416         }
417     }
418     FT_Prop_Set_Func func = (FT_Prop_Set_Func)dlsym(lib, "FT_Property_Set");
419     if (func != NULL) {
420         func(library, module, property, (void*)(&version));
421     }
422     dlclose(lib);
423 #endif
424 }
425 
426 /*
427  * FT_GlyphSlot_Embolden (ftsynth.c) uses FT_MulFix(upem, y_scale) / 24
428  * I prefer something a little less bold, so using 32 instead of 24.
429  */
430 #define BOLD_DIVISOR (32)
431 #define BOLD_FACTOR(units_per_EM, y_scale) \
432     ((FT_MulFix(units_per_EM, y_scale) / BOLD_DIVISOR ))
433 
434 #define BOLD_MODIFIER(units_per_EM, y_scale) \
435     (context->doBold ? BOLD_FACTOR(units_per_EM, y_scale) : 0)
436 
GlyphSlot_Embolden(FT_GlyphSlot slot,FT_Matrix transform)437 static void GlyphSlot_Embolden(FT_GlyphSlot slot, FT_Matrix transform) {
438     FT_Pos extra = 0;
439 
440     /*
441      * Does it make sense to embolden an empty image, such as SPACE ?
442      * We'll say no. A fixed width font might be the one case, but
443      * nothing in freetype made provision for this. And freetype would also
444      * have adjusted the metrics of zero advance glyphs (we won't, see below).
445      */
446     if (!slot ||
447         slot->format != FT_GLYPH_FORMAT_OUTLINE ||
448         slot->metrics.width == 0 ||
449         slot->metrics.height == 0)
450     {
451         return;
452     }
453 
454     extra = BOLD_FACTOR(slot->face->units_per_EM,
455                         slot->face->size->metrics.y_scale);
456 
457     /*
458      * It should not matter that the outline is rotated already,
459      * since we are applying the strength equally in X and Y.
460      * If that changes, then it might.
461      */
462     FT_Outline_Embolden(&slot->outline, extra);
463     slot->metrics.width        += extra;
464     slot->metrics.height       += extra;
465 
466     // Some glyphs are meant to be used as marks or diacritics, so
467     // have a shape but do not have an advance.
468     // Let's not adjust the metrics of any glyph that is zero advance.
469     if (slot->linearHoriAdvance == 0) {
470         return;
471     }
472 
473     if (slot->advance.x) {
474         slot->advance.x += FT_MulFix(extra, transform.xx);
475     }
476 
477     if (slot->advance.y) {
478         slot->advance.y += FT_MulFix(extra, transform.yx);
479     }
480 
481     // The following need to be adjusted but no rotation
482     // linear advance is in 16.16 format, extra is 26.6
483     slot->linearHoriAdvance    += extra << 10;
484     // these are pixel values stored in 26.6 format.
485     slot->metrics.horiAdvance  += extra;
486     slot->metrics.vertAdvance  += extra;
487     slot->metrics.horiBearingY += extra;
488 }
489 
490 
491 /*
492  * Class:     sun_font_FreetypeFontScaler
493  * Method:    initNativeScaler
494  * Signature: (Lsun/font/Font2D;IIZI)J
495  */
496 JNIEXPORT jlong JNICALL
Java_sun_font_FreetypeFontScaler_initNativeScaler(JNIEnv * env,jobject scaler,jobject font2D,jint type,jint indexInCollection,jboolean supportsCJK,jint filesize)497 Java_sun_font_FreetypeFontScaler_initNativeScaler(
498         JNIEnv *env, jobject scaler, jobject font2D, jint type,
499         jint indexInCollection, jboolean supportsCJK, jint filesize) {
500     FTScalerInfo* scalerInfo = NULL;
501     FT_Open_Args ft_open_args;
502     int error;
503     jobject bBuffer;
504     scalerInfo = (FTScalerInfo*) calloc(1, sizeof(FTScalerInfo));
505 
506     if (scalerInfo == NULL)
507         return 0;
508 
509     scalerInfo->env = env;
510     scalerInfo->font2D = font2D;
511     scalerInfo->fontDataOffset = 0;
512     scalerInfo->fontDataLength = 0;
513     scalerInfo->fileSize = filesize;
514 
515     /*
516        We can consider sharing freetype library between different
517        scalers. However, Freetype docs suggest to use different libraries
518        for different threads. Also, our architecture implies that single
519        FontScaler object is shared for different sizes/transforms/styles
520        of the same font.
521 
522        On other hand these methods can not be concurrently executed
523        becaused they are "synchronized" in java.
524     */
525     error = FT_Init_FreeType(&scalerInfo->library);
526     if (error) {
527         free(scalerInfo);
528         return 0;
529     }
530     setInterpreterVersion(scalerInfo->library);
531 
532 #define TYPE1_FROM_JAVA        2
533 
534     error = 1; /* triggers memory freeing unless we clear it */
535     if (type == TYPE1_FROM_JAVA) { /* TYPE1 */
536         scalerInfo->fontData = (unsigned char*) malloc(filesize);
537         scalerInfo->directBuffer = NULL;
538         scalerInfo->fontDataLength = filesize;
539 
540         if (scalerInfo->fontData != NULL) {
541             bBuffer = (*env)->NewDirectByteBuffer(env,
542                                               scalerInfo->fontData,
543                                               scalerInfo->fontDataLength);
544             if (bBuffer != NULL) {
545                 (*env)->CallVoidMethod(env, font2D,
546                                    sunFontIDs.readFileMID, bBuffer);
547 
548                 error = FT_New_Memory_Face(scalerInfo->library,
549                                    scalerInfo->fontData,
550                                    scalerInfo->fontDataLength,
551                                    indexInCollection,
552                                    &scalerInfo->face);
553             }
554         }
555     } else { /* Truetype */
556         scalerInfo->fontData = (unsigned char*) malloc(FILEDATACACHESIZE);
557 
558         if (scalerInfo->fontData != NULL) {
559             FT_Stream ftstream = (FT_Stream) calloc(1, sizeof(FT_StreamRec));
560             if (ftstream != NULL) {
561                 scalerInfo->directBuffer = (*env)->NewDirectByteBuffer(env,
562                                            scalerInfo->fontData,
563                                            FILEDATACACHESIZE);
564                 if (scalerInfo->directBuffer != NULL) {
565                     scalerInfo->directBuffer = (*env)->NewGlobalRef(env,
566                                                scalerInfo->directBuffer);
567                     ftstream->base = NULL;
568                     ftstream->size = filesize;
569                     ftstream->pos = 0;
570                     ftstream->read = (FT_Stream_IoFunc) ReadTTFontFileFunc;
571                     ftstream->close = NULL;
572                     ftstream->pathname.pointer = (void *) scalerInfo;
573 
574                     memset(&ft_open_args, 0, sizeof(FT_Open_Args));
575                     ft_open_args.flags = FT_OPEN_STREAM;
576                     ft_open_args.stream = ftstream;
577 
578                     error = FT_Open_Face(scalerInfo->library,
579                                          &ft_open_args,
580                                          indexInCollection,
581                                          &scalerInfo->face);
582                     if (!error) {
583                         scalerInfo->faceStream = ftstream;
584                     }
585                 }
586                 if (error || scalerInfo->directBuffer == NULL) {
587                     free(ftstream);
588                 }
589             }
590         }
591     }
592 
593     if (error) {
594         FT_Done_FreeType(scalerInfo->library);
595         if (scalerInfo->directBuffer != NULL) {
596             (*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
597         }
598         if (scalerInfo->fontData != NULL)
599             free(scalerInfo->fontData);
600         free(scalerInfo);
601         return 0;
602     }
603 
604     return ptr_to_jlong(scalerInfo);
605 }
606 
euclidianDistance(double a,double b)607 static double euclidianDistance(double a, double b) {
608     if (a < 0) a=-a;
609     if (b < 0) b=-b;
610 
611     if (a == 0) return b;
612     if (b == 0) return a;
613 
614     return sqrt(a*a+b*b);
615 }
616 
617 JNIEXPORT jlong JNICALL
Java_sun_font_FreetypeFontScaler_createScalerContextNative(JNIEnv * env,jobject scaler,jlong pScaler,jdoubleArray matrix,jint aa,jint fm,jfloat boldness,jfloat italic)618 Java_sun_font_FreetypeFontScaler_createScalerContextNative(
619         JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix,
620         jint aa, jint fm, jfloat boldness, jfloat italic) {
621     double dmat[4], ptsz;
622     FTScalerContext *context =
623             (FTScalerContext*) calloc(1, sizeof(FTScalerContext));
624     FTScalerInfo *scalerInfo =
625              (FTScalerInfo*) jlong_to_ptr(pScaler);
626 
627     if (context == NULL) {
628         invalidateJavaScaler(env, scaler, NULL);
629         return (jlong) 0;
630     }
631     (*env)->GetDoubleArrayRegion(env, matrix, 0, 4, dmat);
632     ptsz = euclidianDistance(dmat[2], dmat[3]); //i.e. y-size
633     if (ptsz < 1.0) {
634         //text can not be smaller than 1 point
635         ptsz = 1.0;
636     }
637     context->ptsz = (int)(ptsz * 64);
638     context->transform.xx =  FloatToFTFixed((float)dmat[0]/ptsz);
639     context->transform.yx = -FloatToFTFixed((float)dmat[1]/ptsz);
640     context->transform.xy = -FloatToFTFixed((float)dmat[2]/ptsz);
641     context->transform.yy =  FloatToFTFixed((float)dmat[3]/ptsz);
642     context->aaType = aa;
643     context->fmType = fm;
644 
645     /* If using algorithmic styling, the base values are
646      * boldness = 1.0, italic = 0.0.
647      */
648     context->doBold = (boldness != 1.0);
649     context->doItalize = (italic != 0);
650 
651     /* freetype is very keen to use embedded bitmaps, even if it knows
652      * there is a rotation or you asked for antialiasing.
653      * In the rendering path we will check useSBits and disable
654      * bitmaps unless it is set. And here we set it only if none
655      * of the conditions invalidate using it.
656      * Note that we allow embedded bitmaps for the LCD case.
657      */
658     if ((aa != TEXT_AA_ON) && (fm != TEXT_FM_ON) &&
659         !context->doBold && !context->doItalize &&
660         (context->transform.yx == 0) && (context->transform.xy == 0) &&
661         (context->transform.xx > 0) && (context->transform.yy > 0))
662     {
663         context->useSbits = 1;
664     }
665     return ptr_to_jlong(context);
666 }
667 
668 // values used by FreeType (as of version 2.10.1) for italics transformation matrix in FT_GlyphSlot_Oblique
669 #define FT_MATRIX_ONE 0x10000
670 #define FT_MATRIX_OBLIQUE_XY 0x0366A
671 
setupTransform(FT_Matrix * target,FTScalerContext * context)672 static void setupTransform(FT_Matrix* target, FTScalerContext *context) {
673     FT_Matrix* transform = &context->transform;
674     if (context->doItalize) {
675         // we cannot use FT_GlyphSlot_Oblique as it doesn't work well with arbitrary transforms,
676         // so we add corresponding shear transform to the requested glyph transformation
677         target->xx = FT_MATRIX_ONE;
678         target->xy = FT_MATRIX_OBLIQUE_XY;
679         target->yx = 0;
680         target->yy = FT_MATRIX_ONE;
681         FT_Matrix_Multiply(transform, target);
682     } else {
683         target->xx = transform->xx;
684         target->xy = transform->xy;
685         target->yx = transform->yx;
686         target->yy = transform->yy;
687     }
688 }
689 
setupFTContext(JNIEnv * env,jobject font2D,FTScalerInfo * scalerInfo,FTScalerContext * context)690 static int setupFTContext(JNIEnv *env,
691                           jobject font2D,
692                           FTScalerInfo *scalerInfo,
693                           FTScalerContext *context) {
694     FT_Matrix matrix;
695     int errCode = 0;
696 
697     scalerInfo->env = env;
698     scalerInfo->font2D = font2D;
699 
700     if (context != NULL) {
701         setupTransform(&matrix, context);
702         FT_Set_Transform(scalerInfo->face, &matrix, NULL);
703 
704         errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72);
705 
706         if (errCode == 0) {
707             errCode = FT_Activate_Size(scalerInfo->face->size);
708         }
709 
710         FT_Library_SetLcdFilter(scalerInfo->library, FT_LCD_FILTER_DEFAULT);
711     }
712 
713     return errCode;
714 }
715 
716 // using same values as for the transformation matrix
717 #define OBLIQUE_MODIFIER(y)  (context->doItalize ? ((y)*FT_MATRIX_OBLIQUE_XY/FT_MATRIX_ONE) : 0)
718 
719 /*
720  * Class:     sun_font_FreetypeFontScaler
721  * Method:    getFontMetricsNative
722  * Signature: (Lsun/font/Font2D;J)Lsun/font/StrikeMetrics;
723  */
724 JNIEXPORT jobject JNICALL
Java_sun_font_FreetypeFontScaler_getFontMetricsNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler)725 Java_sun_font_FreetypeFontScaler_getFontMetricsNative(
726         JNIEnv *env, jobject scaler, jobject font2D,
727         jlong pScalerContext, jlong pScaler) {
728 
729     jobject metrics;
730     jfloat ax, ay, dx, dy, bx, by, lx, ly, mx, my;
731     jfloat f0 = 0.0;
732     FTScalerContext *context =
733         (FTScalerContext*) jlong_to_ptr(pScalerContext);
734     FTScalerInfo *scalerInfo =
735              (FTScalerInfo*) jlong_to_ptr(pScaler);
736 
737     int errCode;
738 
739     if (isNullScalerContext(context) || scalerInfo == NULL) {
740         return (*env)->NewObject(env,
741                                  sunFontIDs.strikeMetricsClass,
742                                  sunFontIDs.strikeMetricsCtr,
743                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
744     }
745 
746     errCode = setupFTContext(env, font2D, scalerInfo, context);
747 
748     if (errCode) {
749         metrics = (*env)->NewObject(env,
750                                  sunFontIDs.strikeMetricsClass,
751                                  sunFontIDs.strikeMetricsCtr,
752                                  f0, f0, f0, f0, f0, f0, f0, f0, f0, f0);
753         invalidateJavaScaler(env, scaler, scalerInfo);
754         return metrics;
755     }
756 
757     /* This is ugly and has to be reworked.
758        Freetype provide means to add style to glyph but
759        it seems there is no way to adjust metrics accordingly.
760 
761        So, we have to do adust them explicitly and stay consistent with what
762        freetype does to outlines. */
763 
764 
765     /**** Note: only some metrics are affected by styling ***/
766 
767     /* See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=657854 */
768 #define FT_MulFixFloatShift6(a, b) (((float) (a)) * ((float) (b)) / 65536.0 / 64.0)
769 
770 #define contextAwareMetricsX(x, y) \
771     (FTFixedToFloat(context->transform.xx) * (x) - \
772      FTFixedToFloat(context->transform.xy) * (y))
773 
774 #define contextAwareMetricsY(x, y) \
775     (-FTFixedToFloat(context->transform.yx) * (x) + \
776      FTFixedToFloat(context->transform.yy) * (y))
777 
778     /*
779      * See FreeType source code: src/base/ftobjs.c ft_recompute_scaled_metrics()
780      * http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1659
781      */
782     /* ascent */
783     ax = 0;
784     ay = -(jfloat) (FT_MulFixFloatShift6(
785                        ((jlong) scalerInfo->face->ascender),
786                        (jlong) scalerInfo->face->size->metrics.y_scale));
787     /* descent */
788     dx = 0;
789     dy = -(jfloat) (FT_MulFixFloatShift6(
790                        ((jlong) scalerInfo->face->descender),
791                        (jlong) scalerInfo->face->size->metrics.y_scale));
792     /* baseline */
793     bx = by = 0;
794 
795     /* leading */
796     lx = 0;
797     ly = (jfloat) (FT_MulFixFloatShift6(
798                       (jlong) scalerInfo->face->height,
799                       (jlong) scalerInfo->face->size->metrics.y_scale))
800                   + ay - dy;
801     /* max advance */
802     mx = (jfloat) FT26Dot6ToFloat(
803                      scalerInfo->face->size->metrics.max_advance +
804                      OBLIQUE_MODIFIER(scalerInfo->face->size->metrics.height) +
805                      BOLD_MODIFIER(scalerInfo->face->units_per_EM,
806                              scalerInfo->face->size->metrics.y_scale));
807     my = 0;
808 
809     metrics = (*env)->NewObject(env,
810         sunFontIDs.strikeMetricsClass,
811         sunFontIDs.strikeMetricsCtr,
812         contextAwareMetricsX(ax, ay), contextAwareMetricsY(ax, ay),
813         contextAwareMetricsX(dx, dy), contextAwareMetricsY(dx, dy),
814         bx, by,
815         contextAwareMetricsX(lx, ly), contextAwareMetricsY(lx, ly),
816         contextAwareMetricsX(mx, my), contextAwareMetricsY(mx, my));
817 
818     return metrics;
819 }
820 
821 static jlong
822     getGlyphImageNativeInternal(
823         JNIEnv *env, jobject scaler, jobject font2D,
824         jlong pScalerContext, jlong pScaler, jint glyphCode,
825         jboolean renderImage);
826 
827 /*
828  * Class:     sun_font_FreetypeFontScaler
829  * Method:    getGlyphAdvanceNative
830  * Signature: (Lsun/font/Font2D;JI)F
831  */
832 JNIEXPORT jfloat JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode)833 Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative(
834         JNIEnv *env, jobject scaler, jobject font2D,
835         jlong pScalerContext, jlong pScaler, jint glyphCode) {
836 
837    /* This method is rarely used because requests for metrics are usually
838     * coupled with a request for the bitmap and to a large extent the
839     * work can be reused (to find out metrics we may need to hint the glyph).
840     * So, we typically go through the getGlyphImage code path.
841     * When we do get here, we need to pass a parameter which indicates
842     * that we don't need freetype to render the bitmap, and consequently
843     * don't need to allocate our own storage either.
844     * This is also important when enter here requesting metrics for sizes
845     * of text which a large size would be rejected for a bitmap but we
846     * still need the metrics.
847     */
848 
849     GlyphInfo *info;
850     jfloat advance = 0.0f;
851     jlong image;
852 
853     image = getGlyphImageNativeInternal(
854           env, scaler, font2D, pScalerContext, pScaler, glyphCode, JNI_FALSE);
855     info = (GlyphInfo*) jlong_to_ptr(image);
856 
857     if (info != NULL) {
858         advance = info->advanceX;
859         free(info);
860     }
861 
862     return advance;
863 }
864 
865 /*
866  * Class:     sun_font_FreetypeFontScaler
867  * Method:    getGlyphMetricsNative
868  * Signature: (Lsun/font/Font2D;JILjava/awt/geom/Point2D/Float;)V
869  */
870 JNIEXPORT void JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode,jobject metrics)871 Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative(
872         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
873         jlong pScaler, jint glyphCode, jobject metrics) {
874 
875      /* See the comments in getGlyphMetricsNative. They apply here too. */
876      GlyphInfo *info;
877 
878      jlong image = getGlyphImageNativeInternal(
879                                  env, scaler, font2D,
880                                  pScalerContext, pScaler, glyphCode, JNI_FALSE);
881      info = (GlyphInfo*) jlong_to_ptr(image);
882 
883      if (info != NULL) {
884          (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX);
885          (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY);
886          free(info);
887      } else {
888          (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, 0.0f);
889          (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, 0.0f);
890      }
891 }
892 
893 
getNullGlyphImage()894 static GlyphInfo* getNullGlyphImage() {
895     GlyphInfo *glyphInfo =  (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
896     return glyphInfo;
897 }
898 
CopyBW2Grey8(const void * srcImage,int srcRowBytes,void * dstImage,int dstRowBytes,int width,int height)899 static void CopyBW2Grey8(const void* srcImage, int srcRowBytes,
900                          void* dstImage, int dstRowBytes,
901                          int width, int height) {
902     const UInt8* srcRow = (UInt8*)srcImage;
903     UInt8* dstRow = (UInt8*)dstImage;
904     int wholeByteCount = width >> 3;
905     int remainingBitsCount = width & 7;
906     int i, j;
907 
908     while (height--) {
909         const UInt8* src8 = srcRow;
910         UInt8* dstByte = dstRow;
911         unsigned srcValue;
912 
913         srcRow += srcRowBytes;
914         dstRow += dstRowBytes;
915 
916         for (i = 0; i < wholeByteCount; i++) {
917             srcValue = *src8++;
918             for (j = 0; j < 8; j++) {
919                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
920                 srcValue <<= 1;
921             }
922         }
923         if (remainingBitsCount) {
924             srcValue = *src8;
925             for (j = 0; j < remainingBitsCount; j++) {
926                 *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
927                 srcValue <<= 1;
928             }
929         }
930     }
931 }
932 
933 #define Grey4ToAlpha255(value) (((value) << 4) + ((value) >> 3))
934 
CopyGrey4ToGrey8(const void * srcImage,int srcRowBytes,void * dstImage,int dstRowBytes,int width,int height)935 static void CopyGrey4ToGrey8(const void* srcImage, int srcRowBytes,
936                 void* dstImage, int dstRowBytes, int width, int height) {
937      const UInt8* srcRow = (UInt8*) srcImage;
938      UInt8* dstRow = (UInt8*) dstImage;
939      int i;
940 
941      while (height--) {
942          const UInt8* src8 = srcRow;
943          UInt8* dstByte = dstRow;
944          unsigned srcValue;
945 
946          srcRow += srcRowBytes;
947          dstRow += dstRowBytes;
948 
949          for (i = 0; i < width; i++) {
950              srcValue = *src8++;
951              *dstByte++ = Grey4ToAlpha255(srcValue & 0x0f);
952              *dstByte++ = Grey4ToAlpha255(srcValue >> 4);
953          }
954      }
955 }
956 
957 /* We need it because FT rows are often padded to 4 byte boundaries
958     and our internal format is not padded */
CopyFTSubpixelToSubpixel(const void * srcImage,int srcRowBytes,void * dstImage,int dstRowBytes,int width,int height)959 static void CopyFTSubpixelToSubpixel(const void* srcImage, int srcRowBytes,
960                                      void* dstImage, int dstRowBytes,
961                                      int width, int height) {
962     unsigned char *srcRow = (unsigned char *) srcImage;
963     unsigned char *dstRow = (unsigned char *) dstImage;
964 
965     while (height--) {
966         memcpy(dstRow, srcRow, width);
967         srcRow += srcRowBytes;
968         dstRow += dstRowBytes;
969     }
970 }
971 
972 /* We need it because FT rows are often padded to 4 byte boundaries
973    and our internal format is not padded */
CopyFTSubpixelVToSubpixel(const void * srcImage,int srcRowBytes,void * dstImage,int dstRowBytes,int width,int height)974 static void CopyFTSubpixelVToSubpixel(const void* srcImage, int srcRowBytes,
975                                       void* dstImage, int dstRowBytes,
976                                       int width, int height) {
977     unsigned char *srcRow = (unsigned char *) srcImage, *srcByte;
978     unsigned char *dstRow = (unsigned char *) dstImage, *dstByte;
979     int i;
980 
981     while (height > 0) {
982         srcByte = srcRow;
983         dstByte = dstRow;
984         for (i = 0; i < width; i++) {
985             *dstByte++ = *srcByte;
986             *dstByte++ = *(srcByte + srcRowBytes);
987             *dstByte++ = *(srcByte + 2*srcRowBytes);
988             srcByte++;
989         }
990         srcRow += 3*srcRowBytes;
991         dstRow += dstRowBytes;
992         height -= 3;
993     }
994 }
995 
996 
997 /* JDK does not use glyph images for fonts with a
998  * pixel size > 100 (see THRESHOLD in OutlineTextRenderer.java)
999  * so if the glyph bitmap image dimension is > 1024 pixels,
1000  * something is up.
1001  */
1002 #define MAX_GLYPH_DIM 1024
1003 
1004 /*
1005  * Class:     sun_font_FreetypeFontScaler
1006  * Method:    getGlyphImageNative
1007  * Signature: (Lsun/font/Font2D;JI)J
1008  */
1009 JNIEXPORT jlong JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphImageNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode)1010 Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
1011         JNIEnv *env, jobject scaler, jobject font2D,
1012         jlong pScalerContext, jlong pScaler, jint glyphCode) {
1013 
1014     return getGlyphImageNativeInternal(
1015         env, scaler, font2D,
1016         pScalerContext, pScaler, glyphCode, JNI_TRUE);
1017 }
1018 
1019 static jlong
getGlyphImageNativeInternal(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode,jboolean renderImage)1020      getGlyphImageNativeInternal(
1021         JNIEnv *env, jobject scaler, jobject font2D,
1022         jlong pScalerContext, jlong pScaler, jint glyphCode,
1023         jboolean renderImage) {
1024 
1025     static int PADBYTES = 3;
1026     int error, imageSize;
1027     UInt16 width, height, rowBytes;
1028     GlyphInfo *glyphInfo;
1029     int renderFlags = FT_LOAD_DEFAULT, target;
1030     FT_GlyphSlot ftglyph;
1031 
1032     FTScalerContext* context =
1033         (FTScalerContext*) jlong_to_ptr(pScalerContext);
1034     FTScalerInfo *scalerInfo =
1035              (FTScalerInfo*) jlong_to_ptr(pScaler);
1036 
1037     if (isNullScalerContext(context) || scalerInfo == NULL) {
1038         return ptr_to_jlong(getNullGlyphImage());
1039     }
1040 
1041     error = setupFTContext(env, font2D, scalerInfo, context);
1042     if (error) {
1043         invalidateJavaScaler(env, scaler, scalerInfo);
1044         return ptr_to_jlong(getNullGlyphImage());
1045     }
1046 
1047     /*
1048      * When using Fractional metrics (linearly scaling advances) and
1049      * greyscale antialiasing, disable hinting so that the glyph shapes
1050      * are constant as size increases. This is good for animation as well
1051      * as being compatible with what happened in earlier JDK versions
1052      * which did not use freetype.
1053      */
1054     if (context->aaType == TEXT_AA_ON && context->fmType == TEXT_FM_ON) {
1055          renderFlags |= FT_LOAD_NO_HINTING;
1056      }
1057 
1058     RenderingProperties renderingProperties;
1059     readFontconfig((const FcChar8 *) scalerInfo->face->family_name,
1060                    context->ptsz, context->aaType, &renderingProperties);
1061 
1062     FT_Library_SetLcdFilter(scalerInfo->library, renderingProperties.ftLcdFilter);
1063     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderingProperties.ftLoadFlags);
1064     if (error) {
1065         //do not destroy scaler yet.
1066         //this can be problem of particular context (e.g. with bad transform)
1067         return ptr_to_jlong(getNullGlyphImage());
1068     }
1069 
1070     ftglyph = scalerInfo->face->glyph;
1071 
1072     /* apply styles */
1073     if (context->doBold) { /* if bold style */
1074         GlyphSlot_Embolden(ftglyph, context->transform);
1075     }
1076 
1077     /* generate bitmap if it is not done yet
1078      e.g. if algorithmic styling is performed and style was added to outline */
1079     if (renderImage && (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE)) {
1080         FT_BBox bbox;
1081         FT_Outline_Get_CBox(&(ftglyph->outline), &bbox);
1082         int w = (int)((bbox.xMax>>6)-(bbox.xMin>>6));
1083         int h = (int)((bbox.yMax>>6)-(bbox.yMin>>6));
1084         if (w > MAX_GLYPH_DIM || h > MAX_GLYPH_DIM) {
1085             glyphInfo = getNullGlyphImage();
1086             return ptr_to_jlong(glyphInfo);
1087         }
1088     }
1089     error = FT_Render_Glyph(ftglyph, renderingProperties.ftRenderMode);
1090     if (error != 0) {
1091         return ptr_to_jlong(getNullGlyphImage());
1092     }
1093 
1094     if (renderImage) {
1095         width  = (UInt16) ftglyph->bitmap.width;
1096         rowBytes = width;
1097         if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
1098            rowBytes = PADBYTES + width + PADBYTES;
1099         }
1100         height = (UInt16) ftglyph->bitmap.rows;
1101             if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) {
1102               glyphInfo = getNullGlyphImage();
1103               return ptr_to_jlong(glyphInfo);
1104             }
1105      } else {
1106         width = 0;
1107         rowBytes = 0;
1108         height = 0;
1109      }
1110 
1111 
1112     imageSize = rowBytes*height;
1113     glyphInfo = (GlyphInfo*) calloc(sizeof(GlyphInfo) + imageSize, 1);
1114     if (glyphInfo == NULL) {
1115         glyphInfo = getNullGlyphImage();
1116         return ptr_to_jlong(glyphInfo);
1117     }
1118     glyphInfo->cellInfo  = NULL;
1119     glyphInfo->managed   = UNMANAGED_GLYPH;
1120     glyphInfo->rowBytes  = rowBytes;
1121     glyphInfo->width     = width;
1122     glyphInfo->height    = height;
1123 
1124     if (renderImage) {
1125         glyphInfo->topLeftX  = (float)  ftglyph->bitmap_left;
1126         glyphInfo->topLeftY  = (float) -ftglyph->bitmap_top;
1127 
1128         if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD && width > 0) {
1129             glyphInfo->width = width/3;
1130             glyphInfo->topLeftX -= 1;
1131             glyphInfo->width += 1;
1132         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
1133             glyphInfo->height = glyphInfo->height/3;
1134         }
1135     }
1136 
1137     if (context->fmType == TEXT_FM_ON) {
1138         float advh = FTFixedToFloat(ftglyph->linearHoriAdvance);
1139         glyphInfo->advanceX =
1140             (float) (advh * FTFixedToFloat(context->transform.xx));
1141         glyphInfo->advanceY =
1142             (float) - (advh * FTFixedToFloat(context->transform.yx));
1143     } else {
1144         if (!ftglyph->advance.y) {
1145             glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x);
1146             glyphInfo->advanceY = 0;
1147         } else if (!ftglyph->advance.x) {
1148             glyphInfo->advanceX = 0;
1149             glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y);
1150         } else {
1151             glyphInfo->advanceX = FT26Dot6ToFloat(ftglyph->advance.x);
1152             glyphInfo->advanceY = FT26Dot6ToFloat(-ftglyph->advance.y);
1153         }
1154     }
1155 
1156     if (imageSize == 0) {
1157         glyphInfo->image = NULL;
1158     } else {
1159         glyphInfo->image = (unsigned char*) glyphInfo + sizeof(GlyphInfo);
1160         //convert result to output format
1161         //output format is either 3 bytes per pixel (for subpixel modes)
1162         // or 1 byte per pixel for AA and B&W
1163         if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_MONO) {
1164             /* convert from 8 pixels per byte to 1 byte per pixel */
1165             CopyBW2Grey8(ftglyph->bitmap.buffer,
1166                          ftglyph->bitmap.pitch,
1167                          (void *) glyphInfo->image,
1168                          width,
1169                          width,
1170                          height);
1171         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY) {
1172             /* byte per pixel to byte per pixel => just copy */
1173             memcpy(glyphInfo->image, ftglyph->bitmap.buffer, imageSize);
1174         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_GRAY4) {
1175             /* 4 bits per pixel to byte per pixel */
1176             CopyGrey4ToGrey8(ftglyph->bitmap.buffer,
1177                              ftglyph->bitmap.pitch,
1178                              (void *) glyphInfo->image,
1179                              width,
1180                              width,
1181                              height);
1182         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD) {
1183             /* 3 bytes per pixel to 3 bytes per pixel */
1184             CopyFTSubpixelToSubpixel(ftglyph->bitmap.buffer,
1185                                      ftglyph->bitmap.pitch,
1186                                      (void *) (glyphInfo->image+PADBYTES),
1187                                      rowBytes,
1188                                      width,
1189                                      height);
1190         } else if (ftglyph->bitmap.pixel_mode ==  FT_PIXEL_MODE_LCD_V) {
1191             /* 3 bytes per pixel to 3 bytes per pixel */
1192             CopyFTSubpixelVToSubpixel(ftglyph->bitmap.buffer,
1193                                       ftglyph->bitmap.pitch,
1194                                       (void *) glyphInfo->image,
1195                                       width*3,
1196                                       width,
1197                                       height);
1198             glyphInfo->rowBytes *=3;
1199         } else {
1200             free(glyphInfo);
1201             glyphInfo = getNullGlyphImage();
1202         }
1203     }
1204 
1205     return ptr_to_jlong(glyphInfo);
1206 }
1207 
1208 /*
1209  * Class:     sun_font_FreetypeFontScaler
1210  * Method:    disposeNativeScaler
1211  * Signature: (J)V
1212  */
1213 JNIEXPORT void JNICALL
Java_sun_font_FreetypeFontScaler_disposeNativeScaler(JNIEnv * env,jobject scaler,jobject font2D,jlong pScaler)1214 Java_sun_font_FreetypeFontScaler_disposeNativeScaler(
1215         JNIEnv *env, jobject scaler, jobject font2D, jlong pScaler) {
1216     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1217 
1218     /* Freetype functions *may* cause callback to java
1219        that can use cached values. Make sure our cache is up to date.
1220        NB: scaler context is not important at this point, can use NULL. */
1221     int errCode = setupFTContext(env, font2D, scalerInfo, NULL);
1222     if (errCode) {
1223         return;
1224     }
1225 
1226     freeNativeResources(env, scalerInfo);
1227 }
1228 
1229 /*
1230  * Class:     sun_font_FreetypeFontScaler
1231  * Method:    getNumGlyphsNative
1232  * Signature: ()I
1233  */
1234 JNIEXPORT jint JNICALL
Java_sun_font_FreetypeFontScaler_getNumGlyphsNative(JNIEnv * env,jobject scaler,jlong pScaler)1235 Java_sun_font_FreetypeFontScaler_getNumGlyphsNative(
1236         JNIEnv *env, jobject scaler, jlong pScaler) {
1237     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1238 
1239     if (scalerInfo == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
1240         /* null scaler can render 1 glyph - "missing glyph" with code 0
1241            (all glyph codes requested by user are mapped to code 0 at
1242            validation step) */
1243         invalidateJavaScaler(env, scaler, scalerInfo);
1244         return (jint) 1;
1245     }
1246 
1247     return (jint) scalerInfo->face->num_glyphs;
1248 }
1249 
1250 /*
1251  * Class:     sun_font_FreetypeFontScaler
1252  * Method:    getMissingGlyphCodeNative
1253  * Signature: ()I
1254  */
1255 JNIEXPORT jint JNICALL
Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative(JNIEnv * env,jobject scaler,jlong pScaler)1256 Java_sun_font_FreetypeFontScaler_getMissingGlyphCodeNative(
1257         JNIEnv *env, jobject scaler, jlong pScaler) {
1258 
1259     /* Is it always 0 for freetype? */
1260     return 0;
1261 }
1262 
1263 /*
1264  * Class:     sun_font_FreetypeFontScaler
1265  * Method:    getGlyphCodeNative
1266  * Signature: (C)I
1267  */
1268 JNIEXPORT jint JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScaler,jchar charCode)1269 Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(
1270         JNIEnv *env, jobject scaler,
1271         jobject font2D, jlong pScaler, jchar charCode) {
1272 
1273     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1274     int errCode;
1275 
1276     if (scaler == NULL || scalerInfo->face == NULL) { /* bad/null scaler */
1277         invalidateJavaScaler(env, scaler, scalerInfo);
1278         return 0;
1279     }
1280 
1281     /* Freetype functions *may* cause callback to java
1282        that can use cached values. Make sure our cache is up to date.
1283        Scaler context is not important here, can use NULL. */
1284     errCode = setupFTContext(env, font2D, scalerInfo, NULL);
1285     if (errCode) {
1286         return 0;
1287     }
1288 
1289     return FT_Get_Char_Index(scalerInfo->face, charCode);
1290 }
1291 
1292 
1293 #define FloatToF26Dot6(x) ((unsigned int) ((x)*64))
1294 
getFTOutline(JNIEnv * env,jobject font2D,FTScalerContext * context,FTScalerInfo * scalerInfo,jint glyphCode,jfloat xpos,jfloat ypos)1295 static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
1296         FTScalerContext *context, FTScalerInfo* scalerInfo,
1297         jint glyphCode, jfloat xpos, jfloat ypos) {
1298     int renderFlags;
1299     FT_Error error;
1300     FT_GlyphSlot ftglyph;
1301 
1302     if (glyphCode >= INVISIBLE_GLYPHS ||
1303             isNullScalerContext(context) || scalerInfo == NULL) {
1304         return NULL;
1305     }
1306 
1307     error = setupFTContext(env, font2D, scalerInfo, context);
1308     if (error) {
1309         return NULL;
1310     }
1311 
1312     RenderingProperties renderingProperties;
1313     readFontconfig((const FcChar8 *) scalerInfo->face->family_name,
1314                    context->ptsz, context->aaType, &renderingProperties);
1315 
1316     error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderingProperties.ftLoadFlags);
1317     if (error) {
1318         return NULL;
1319     }
1320 
1321     ftglyph = scalerInfo->face->glyph;
1322 
1323     /* apply styles */
1324     if (context->doBold) { /* if bold style */
1325         GlyphSlot_Embolden(ftglyph, context->transform);
1326     }
1327 
1328     FT_Outline_Translate(&ftglyph->outline,
1329                          FloatToF26Dot6(xpos),
1330                          FloatToF26Dot6(-ypos));
1331 
1332     return &ftglyph->outline;
1333 }
1334 
1335 #define F26Dot6ToFloat(n) (((float)(n))/((float) 64))
1336 
1337 /* Types of GeneralPath segments.
1338    TODO: pull constants from other place? */
1339 
1340 #define SEG_UNKNOWN -1
1341 #define SEG_MOVETO   0
1342 #define SEG_LINETO   1
1343 #define SEG_QUADTO   2
1344 #define SEG_CUBICTO  3
1345 #define SEG_CLOSE    4
1346 
1347 #define WIND_NON_ZERO 0
1348 #define WIND_EVEN_ODD 1
1349 
1350 /* Placeholder to accumulate GeneralPath data */
1351 typedef struct {
1352     jint numTypes;
1353     jint numCoords;
1354     jint lenTypes;
1355     jint lenCoords;
1356     jint wr;
1357     jbyte* pointTypes;
1358     jfloat* pointCoords;
1359 } GPData;
1360 
1361 /* returns 0 on failure */
allocateSpaceForGP(GPData * gpdata,int npoints,int ncontours)1362 static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) {
1363     int maxTypes, maxCoords;
1364 
1365     /* we may have up to N intermediate points per contour
1366        (and for each point can actually cause new curve to be generated)
1367        In addition we can also have 2 extra point per outline.
1368      */
1369     maxTypes  = 2*npoints  + 2*ncontours;
1370     maxCoords = 4*(npoints + 2*ncontours); //we may need to insert
1371                                            //up to n-1 intermediate points
1372 
1373     /* first usage - allocate space and intialize all fields */
1374     if (gpdata->pointTypes == NULL || gpdata->pointCoords == NULL) {
1375         gpdata->lenTypes  = maxTypes;
1376         gpdata->lenCoords = maxCoords;
1377         gpdata->pointTypes  = (jbyte*)
1378              malloc(gpdata->lenTypes*sizeof(jbyte));
1379         gpdata->pointCoords = (jfloat*)
1380              malloc(gpdata->lenCoords*sizeof(jfloat));
1381         gpdata->numTypes = 0;
1382         gpdata->numCoords = 0;
1383         gpdata->wr = WIND_NON_ZERO; /* By default, outlines are filled
1384                                        using the non-zero winding rule. */
1385     } else {
1386         /* do we have enough space? */
1387         if (gpdata->lenTypes - gpdata->numTypes < maxTypes) {
1388             gpdata->lenTypes  += maxTypes;
1389             gpdata->pointTypes  = (jbyte*)
1390               realloc(gpdata->pointTypes, gpdata->lenTypes*sizeof(jbyte));
1391         }
1392 
1393         if (gpdata->lenCoords - gpdata->numCoords < maxCoords) {
1394             gpdata->lenCoords += maxCoords;
1395             gpdata->pointCoords = (jfloat*)
1396               realloc(gpdata->pointCoords, gpdata->lenCoords*sizeof(jfloat));
1397         }
1398     }
1399 
1400     /* failure if any of mallocs failed */
1401     if (gpdata->pointTypes == NULL ||  gpdata->pointCoords == NULL)
1402         return 0;
1403     else
1404         return 1;
1405 }
1406 
addSeg(GPData * gp,jbyte type)1407 static void addSeg(GPData *gp, jbyte type) {
1408     gp->pointTypes[gp->numTypes++] = type;
1409 }
1410 
addCoords(GPData * gp,FT_Vector * p)1411 static void addCoords(GPData *gp, FT_Vector *p) {
1412     gp->pointCoords[gp->numCoords++] =  F26Dot6ToFloat(p->x);
1413     gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y);
1414 }
1415 
moveTo(FT_Vector * to,GPData * gp)1416 static int moveTo(FT_Vector *to, GPData *gp) {
1417     if (gp->numCoords)
1418         addSeg(gp, SEG_CLOSE);
1419     addCoords(gp, to);
1420     addSeg(gp, SEG_MOVETO);
1421     return FT_Err_Ok;
1422 }
1423 
lineTo(FT_Vector * to,GPData * gp)1424 static int lineTo(FT_Vector *to, GPData *gp) {
1425     addCoords(gp, to);
1426     addSeg(gp, SEG_LINETO);
1427     return FT_Err_Ok;
1428 }
1429 
conicTo(FT_Vector * control,FT_Vector * to,GPData * gp)1430 static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) {
1431     addCoords(gp, control);
1432     addCoords(gp, to);
1433     addSeg(gp, SEG_QUADTO);
1434     return FT_Err_Ok;
1435 }
1436 
cubicTo(FT_Vector * control1,FT_Vector * control2,FT_Vector * to,GPData * gp)1437 static int cubicTo(FT_Vector *control1,
1438                    FT_Vector *control2,
1439                    FT_Vector *to,
1440                    GPData    *gp) {
1441     addCoords(gp, control1);
1442     addCoords(gp, control2);
1443     addCoords(gp, to);
1444     addSeg(gp, SEG_CUBICTO);
1445     return FT_Err_Ok;
1446 }
1447 
addToGP(GPData * gpdata,FT_Outline * outline)1448 static void addToGP(GPData* gpdata, FT_Outline*outline) {
1449     static const FT_Outline_Funcs outline_funcs = {
1450         (FT_Outline_MoveToFunc) moveTo,
1451         (FT_Outline_LineToFunc) lineTo,
1452         (FT_Outline_ConicToFunc) conicTo,
1453         (FT_Outline_CubicToFunc) cubicTo,
1454         0, /* shift */
1455         0, /* delta */
1456     };
1457 
1458     FT_Outline_Decompose(outline, &outline_funcs, gpdata);
1459     if (gpdata->numCoords)
1460         addSeg(gpdata, SEG_CLOSE);
1461 
1462     /* If set to 1, the outline will be filled using the even-odd fill rule */
1463     if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) {
1464         gpdata->wr = WIND_EVEN_ODD;
1465     }
1466 }
1467 
freeGP(GPData * gpdata)1468 static void freeGP(GPData* gpdata) {
1469     if (gpdata->pointCoords != NULL) {
1470         free(gpdata->pointCoords);
1471         gpdata->pointCoords = NULL;
1472         gpdata->numCoords = 0;
1473         gpdata->lenCoords = 0;
1474     }
1475     if (gpdata->pointTypes != NULL) {
1476         free(gpdata->pointTypes);
1477         gpdata->pointTypes = NULL;
1478         gpdata->numTypes = 0;
1479         gpdata->lenTypes = 0;
1480     }
1481 }
1482 
getGlyphGeneralPath(JNIEnv * env,jobject font2D,FTScalerContext * context,FTScalerInfo * scalerInfo,jint glyphCode,jfloat xpos,jfloat ypos)1483 static jobject getGlyphGeneralPath(JNIEnv* env, jobject font2D,
1484         FTScalerContext *context, FTScalerInfo *scalerInfo,
1485         jint glyphCode, jfloat xpos, jfloat ypos) {
1486 
1487     FT_Outline* outline;
1488     jobject gp = NULL;
1489     jbyteArray types;
1490     jfloatArray coords;
1491     GPData gpdata;
1492 
1493     outline = getFTOutline(env, font2D, context, scalerInfo,
1494                            glyphCode, xpos, ypos);
1495 
1496     if (outline == NULL || outline->n_points == 0) {
1497         return gp;
1498     }
1499 
1500     gpdata.pointTypes  = NULL;
1501     gpdata.pointCoords = NULL;
1502     if (!allocateSpaceForGP(&gpdata, outline->n_points, outline->n_contours)) {
1503         return gp;
1504     }
1505 
1506     addToGP(&gpdata, outline);
1507 
1508     types  = (*env)->NewByteArray(env, gpdata.numTypes);
1509     coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1510 
1511     if (types && coords) {
1512         (*env)->SetByteArrayRegion(env, types, 0,
1513                                    gpdata.numTypes,
1514                                    gpdata.pointTypes);
1515         (*env)->SetFloatArrayRegion(env, coords, 0,
1516                                     gpdata.numCoords,
1517                                     gpdata.pointCoords);
1518         gp = (*env)->NewObject(env,
1519                                sunFontIDs.gpClass,
1520                                sunFontIDs.gpCtr,
1521                                gpdata.wr,
1522                                types,
1523                                gpdata.numTypes,
1524                                coords,
1525                                gpdata.numCoords);
1526     }
1527 
1528     freeGP(&gpdata);
1529 
1530     return gp;
1531 }
1532 
1533 /*
1534  * Class:     sun_font_FreetypeFontScaler
1535  * Method:    getGlyphOutlineNative
1536  * Signature: (Lsun/font/Font2D;JIFF)Ljava/awt/geom/GeneralPath;
1537  */
1538 JNIEXPORT jobject JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode,jfloat xpos,jfloat ypos)1539 Java_sun_font_FreetypeFontScaler_getGlyphOutlineNative(
1540       JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1541       jlong pScaler, jint glyphCode, jfloat xpos, jfloat ypos) {
1542 
1543     FTScalerContext *context =
1544          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1545     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1546 
1547     jobject gp = getGlyphGeneralPath(env,
1548                                font2D,
1549                                context,
1550                                scalerInfo,
1551                                glyphCode,
1552                                xpos,
1553                                ypos);
1554     if (gp == NULL) { /* can be legal */
1555         gp = (*env)->NewObject(env,
1556                                sunFontIDs.gpClass,
1557                                sunFontIDs.gpCtrEmpty);
1558     }
1559     return gp;
1560 }
1561 
1562 /*
1563  * Class:     sun_font_FreetypeFontScaler
1564  * Method:    getGlyphOutlineBoundsNative
1565  * Signature: (Lsun/font/Font2D;JI)Ljava/awt/geom/Rectangle2D/Float;
1566  */
1567 JNIEXPORT jobject JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode)1568 Java_sun_font_FreetypeFontScaler_getGlyphOutlineBoundsNative(
1569         JNIEnv *env, jobject scaler, jobject font2D,
1570         jlong pScalerContext, jlong pScaler, jint glyphCode) {
1571 
1572     FT_Outline *outline;
1573     FT_BBox bbox;
1574     int error;
1575     jobject bounds;
1576 
1577     FTScalerContext *context =
1578          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1579     FTScalerInfo* scalerInfo = (FTScalerInfo *) jlong_to_ptr(pScaler);
1580 
1581     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1582     if (outline == NULL || outline->n_points == 0) {
1583         /* it is legal case, e.g. invisible glyph */
1584         bounds = (*env)->NewObject(env,
1585                                  sunFontIDs.rect2DFloatClass,
1586                                  sunFontIDs.rect2DFloatCtr);
1587         return bounds;
1588     }
1589 
1590     error = FT_Outline_Get_BBox(outline, &bbox);
1591 
1592     //convert bbox
1593     if (error || bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) {
1594         bounds = (*env)->NewObject(env,
1595                                    sunFontIDs.rect2DFloatClass,
1596                                    sunFontIDs.rect2DFloatCtr);
1597     } else {
1598         bounds = (*env)->NewObject(env,
1599                                    sunFontIDs.rect2DFloatClass,
1600                                    sunFontIDs.rect2DFloatCtr4,
1601                                    F26Dot6ToFloat(bbox.xMin),
1602                                    F26Dot6ToFloat(-bbox.yMax),
1603                                    F26Dot6ToFloat(bbox.xMax-bbox.xMin),
1604                                    F26Dot6ToFloat(bbox.yMax-bbox.yMin));
1605     }
1606 
1607     return bounds;
1608 }
1609 
1610 /*
1611  * Class:     sun_font_FreetypeFontScaler
1612  * Method:    getGlyphVectorOutlineNative
1613  * Signature: (Lsun/font/Font2D;J[IIFF)Ljava/awt/geom/GeneralPath;
1614  */
1615 JNIEXPORT jobject
1616 JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jintArray glyphArray,jint numGlyphs,jfloat xpos,jfloat ypos)1617 Java_sun_font_FreetypeFontScaler_getGlyphVectorOutlineNative(
1618         JNIEnv *env, jobject scaler, jobject font2D,
1619         jlong pScalerContext, jlong pScaler,
1620         jintArray glyphArray, jint numGlyphs, jfloat xpos, jfloat ypos) {
1621 
1622     FT_Outline* outline;
1623     jobject gp = NULL;
1624     jbyteArray types;
1625     jfloatArray coords;
1626     GPData gpdata;
1627     int i;
1628     jint *glyphs;
1629 
1630     FTScalerContext *context =
1631          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1632     FTScalerInfo *scalerInfo =
1633              (FTScalerInfo*) jlong_to_ptr(pScaler);
1634 
1635     glyphs = NULL;
1636     if (numGlyphs > 0 && 0xffffffffu / sizeof(jint) >= (unsigned int)numGlyphs) {
1637         glyphs = (jint*) malloc(numGlyphs*sizeof(jint));
1638     }
1639     if (glyphs == NULL) {
1640         // We reach here if:
1641         // 1. numGlyphs <= 0,
1642         // 2. overflow check failed, or
1643         // 3. malloc failed.
1644         gp = (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1645         return gp;
1646     }
1647 
1648     (*env)->GetIntArrayRegion(env, glyphArray, 0, numGlyphs, glyphs);
1649 
1650     gpdata.numCoords = 0;
1651     for (i=0; i<numGlyphs;i++) {
1652         if (glyphs[i] >= INVISIBLE_GLYPHS) {
1653             continue;
1654         }
1655         outline = getFTOutline(env,
1656                                font2D,
1657                                context,
1658                                scalerInfo,
1659                                glyphs[i],
1660                                xpos, ypos);
1661 
1662         if (outline == NULL || outline->n_points == 0) {
1663             continue;
1664         }
1665 
1666         gpdata.pointTypes  = NULL;
1667         gpdata.pointCoords = NULL;
1668         if (!allocateSpaceForGP(&gpdata, outline->n_points,
1669                                 outline->n_contours)) {
1670             break;
1671         }
1672 
1673         addToGP(&gpdata, outline);
1674     }
1675     free(glyphs);
1676 
1677     if (gpdata.numCoords != 0) {
1678       types = (*env)->NewByteArray(env, gpdata.numTypes);
1679       coords = (*env)->NewFloatArray(env, gpdata.numCoords);
1680 
1681       if (types && coords) {
1682         (*env)->SetByteArrayRegion(env, types, 0,
1683                                    gpdata.numTypes, gpdata.pointTypes);
1684         (*env)->SetFloatArrayRegion(env, coords, 0,
1685                                     gpdata.numCoords, gpdata.pointCoords);
1686 
1687         gp=(*env)->NewObject(env,
1688                              sunFontIDs.gpClass,
1689                              sunFontIDs.gpCtr,
1690                              gpdata.wr,
1691                              types,
1692                              gpdata.numTypes,
1693                              coords,
1694                              gpdata.numCoords);
1695         return gp;
1696       }
1697     }
1698     return (*env)->NewObject(env, sunFontIDs.gpClass, sunFontIDs.gpCtrEmpty);
1699 }
1700 
1701 JNIEXPORT jlong JNICALL
Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative(JNIEnv * env,jobject scaler,jlong pScaler)1702 Java_sun_font_FreetypeFontScaler_getUnitsPerEMNative(
1703         JNIEnv *env, jobject scaler, jlong pScaler) {
1704 
1705     FTScalerInfo *s = (FTScalerInfo* ) jlong_to_ptr(pScaler);
1706 
1707     /* Freetype doc says:
1708      The number of font units per EM square for this face.
1709      This is typically 2048 for TrueType fonts, and 1000 for Type 1 fonts.
1710      Only relevant for scalable formats.
1711      However, layout engine might be not tested with anything but 2048.
1712 
1713      NB: test it! */
1714     if (s != NULL) {
1715         return s->face->units_per_EM;
1716     }
1717     return 2048;
1718 }
1719 
1720 /* This native method is called by the OpenType layout engine. */
1721 JNIEXPORT jobject JNICALL
Java_sun_font_FreetypeFontScaler_getGlyphPointNative(JNIEnv * env,jobject scaler,jobject font2D,jlong pScalerContext,jlong pScaler,jint glyphCode,jint pointNumber)1722 Java_sun_font_FreetypeFontScaler_getGlyphPointNative(
1723         JNIEnv *env, jobject scaler, jobject font2D, jlong pScalerContext,
1724         jlong pScaler, jint glyphCode, jint pointNumber) {
1725 
1726     FT_Outline* outline;
1727     jobject point = NULL;
1728     jfloat x=0, y=0;
1729     FTScalerContext *context =
1730          (FTScalerContext*) jlong_to_ptr(pScalerContext);
1731     FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
1732 
1733     outline = getFTOutline(env, font2D, context, scalerInfo, glyphCode, 0, 0);
1734 
1735     if (outline != NULL && outline->n_points > pointNumber) {
1736         x =  F26Dot6ToFloat(outline->points[pointNumber].x);
1737         y = -F26Dot6ToFloat(outline->points[pointNumber].y);
1738     }
1739 
1740     return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
1741                              sunFontIDs.pt2DFloatCtr, x, y);
1742 }
1743