Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c
41159 views
1
/*
2
* Copyright (c) 2003, 2013, 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
#ifndef HEADLESS
27
28
#include <stdlib.h>
29
#include <math.h>
30
#include <jlong.h>
31
32
#include "sun_java2d_opengl_OGLTextRenderer.h"
33
34
#include "SurfaceData.h"
35
#include "OGLContext.h"
36
#include "OGLSurfaceData.h"
37
#include "OGLRenderQueue.h"
38
#include "OGLTextRenderer.h"
39
#include "OGLVertexCache.h"
40
#include "AccelGlyphCache.h"
41
#include "fontscalerdefs.h"
42
43
/**
44
* The following constants define the inner and outer bounds of the
45
* accelerated glyph cache.
46
*/
47
#define OGLTR_CACHE_WIDTH 512
48
#define OGLTR_CACHE_HEIGHT 512
49
#define OGLTR_CACHE_CELL_WIDTH 32
50
#define OGLTR_CACHE_CELL_HEIGHT 32
51
52
/**
53
* The current "glyph mode" state. This variable is used to track the
54
* codepath used to render a particular glyph. This variable is reset to
55
* MODE_NOT_INITED at the beginning of every call to OGLTR_DrawGlyphList().
56
* As each glyph is rendered, the glyphMode variable is updated to reflect
57
* the current mode, so if the current mode is the same as the mode used
58
* to render the previous glyph, we can avoid doing costly setup operations
59
* each time.
60
*/
61
typedef enum {
62
MODE_NOT_INITED,
63
MODE_USE_CACHE_GRAY,
64
MODE_USE_CACHE_LCD,
65
MODE_NO_CACHE_GRAY,
66
MODE_NO_CACHE_LCD,
67
MODE_NO_CACHE_COLOR
68
} GlyphMode;
69
static GlyphMode glyphMode = MODE_NOT_INITED;
70
71
/**
72
* There are two separate glyph caches: for AA and for LCD.
73
* Once one of them is initialized as either GRAY or LCD, it
74
* stays in that mode for the duration of the application. It should
75
* be safe to use this one glyph cache for all screens in a multimon
76
* environment, since the glyph cache texture is shared between all contexts,
77
* and (in theory) OpenGL drivers should be smart enough to manage that
78
* texture across all screens.
79
*/
80
81
static GlyphCacheInfo *glyphCacheLCD = NULL;
82
static GlyphCacheInfo *glyphCacheAA = NULL;
83
84
/**
85
* The handle to the LCD text fragment program object.
86
*/
87
static GLhandleARB lcdTextProgram = 0;
88
89
/**
90
* This value tracks the previous LCD contrast setting, so if the contrast
91
* value hasn't changed since the last time the gamma uniforms were
92
* updated (not very common), then we can skip updating the unforms.
93
*/
94
static jint lastLCDContrast = -1;
95
96
/**
97
* This value tracks the previous LCD rgbOrder setting, so if the rgbOrder
98
* value has changed since the last time, it indicates that we need to
99
* invalidate the cache, which may already store glyph images in the reverse
100
* order. Note that in most real world applications this value will not
101
* change over the course of the application, but tests like Font2DTest
102
* allow for changing the ordering at runtime, so we need to handle that case.
103
*/
104
static jboolean lastRGBOrder = JNI_TRUE;
105
106
/**
107
* This constant defines the size of the tile to use in the
108
* OGLTR_DrawLCDGlyphNoCache() method. See below for more on why we
109
* restrict this value to a particular size.
110
*/
111
#define OGLTR_NOCACHE_TILE_SIZE 32
112
113
/**
114
* These constants define the size of the "cached destination" texture.
115
* This texture is only used when rendering LCD-optimized text, as that
116
* codepath needs direct access to the destination. There is no way to
117
* access the framebuffer directly from an OpenGL shader, so we need to first
118
* copy the destination region corresponding to a particular glyph into
119
* this cached texture, and then that texture will be accessed inside the
120
* shader. Copying the destination into this cached texture can be a very
121
* expensive operation (accounting for about half the rendering time for
122
* LCD text), so to mitigate this cost we try to bulk read a horizontal
123
* region of the destination at a time. (These values are empirically
124
* derived for the common case where text runs horizontally.)
125
*
126
* Note: It is assumed in various calculations below that:
127
* (OGLTR_CACHED_DEST_WIDTH >= OGLTR_CACHE_CELL_WIDTH) &&
128
* (OGLTR_CACHED_DEST_WIDTH >= OGLTR_NOCACHE_TILE_SIZE) &&
129
* (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_CACHE_CELL_HEIGHT) &&
130
* (OGLTR_CACHED_DEST_HEIGHT >= OGLTR_NOCACHE_TILE_SIZE)
131
*/
132
#define OGLTR_CACHED_DEST_WIDTH 512
133
#define OGLTR_CACHED_DEST_HEIGHT (OGLTR_CACHE_CELL_HEIGHT * 2)
134
135
/**
136
* The handle to the "cached destination" texture object.
137
*/
138
static GLuint cachedDestTextureID = 0;
139
140
/**
141
* The current bounds of the "cached destination" texture, in destination
142
* coordinate space. The width/height of these bounds will not exceed the
143
* OGLTR_CACHED_DEST_WIDTH/HEIGHT values defined above. These bounds are
144
* only considered valid when the isCachedDestValid flag is JNI_TRUE.
145
*/
146
static SurfaceDataBounds cachedDestBounds;
147
148
/**
149
* This flag indicates whether the "cached destination" texture contains
150
* valid data. This flag is reset to JNI_FALSE at the beginning of every
151
* call to OGLTR_DrawGlyphList(). Once we copy valid destination data
152
* into the cached texture, this flag is set to JNI_TRUE. This way, we can
153
* limit the number of times we need to copy destination data, which is a
154
* very costly operation.
155
*/
156
static jboolean isCachedDestValid = JNI_FALSE;
157
158
/**
159
* The bounds of the previously rendered LCD glyph, in destination
160
* coordinate space. We use these bounds to determine whether the glyph
161
* currently being rendered overlaps the previously rendered glyph (i.e.
162
* its bounding box intersects that of the previously rendered glyph). If
163
* so, we need to re-read the destination area associated with that previous
164
* glyph so that we can correctly blend with the actual destination data.
165
*/
166
static SurfaceDataBounds previousGlyphBounds;
167
168
/**
169
* Initializes the one glyph cache (texture and data structure).
170
* If lcdCache is JNI_TRUE, the texture will contain RGB data,
171
* otherwise we will simply store the grayscale/monochrome glyph images
172
* as intensity values (which work well with the GL_MODULATE function).
173
*/
174
static jboolean
175
OGLTR_InitGlyphCache(jboolean lcdCache)
176
{
177
GlyphCacheInfo *gcinfo;
178
GLclampf priority = 1.0f;
179
GLenum internalFormat = lcdCache ? GL_RGB8 : GL_INTENSITY8;
180
GLenum pixelFormat = lcdCache ? GL_RGB : GL_LUMINANCE;
181
182
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_InitGlyphCache");
183
184
// init glyph cache data structure
185
gcinfo = AccelGlyphCache_Init(OGLTR_CACHE_WIDTH,
186
OGLTR_CACHE_HEIGHT,
187
OGLTR_CACHE_CELL_WIDTH,
188
OGLTR_CACHE_CELL_HEIGHT,
189
OGLVertexCache_FlushVertexCache);
190
if (gcinfo == NULL) {
191
J2dRlsTraceLn(J2D_TRACE_ERROR,
192
"OGLTR_InitGlyphCache: could not init OGL glyph cache");
193
return JNI_FALSE;
194
}
195
196
// init cache texture object
197
j2d_glGenTextures(1, &gcinfo->cacheID);
198
j2d_glBindTexture(GL_TEXTURE_2D, gcinfo->cacheID);
199
j2d_glPrioritizeTextures(1, &gcinfo->cacheID, &priority);
200
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
201
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
202
203
j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
204
OGLTR_CACHE_WIDTH, OGLTR_CACHE_HEIGHT, 0,
205
pixelFormat, GL_UNSIGNED_BYTE, NULL);
206
207
if (lcdCache) {
208
glyphCacheLCD = gcinfo;
209
} else {
210
glyphCacheAA = gcinfo;
211
}
212
213
return JNI_TRUE;
214
}
215
216
/**
217
* Adds the given glyph to the glyph cache (texture and data structure)
218
* associated with the given OGLContext.
219
*/
220
static void
221
OGLTR_AddToGlyphCache(GlyphInfo *glyph, GLenum pixelFormat)
222
{
223
CacheCellInfo *ccinfo;
224
GlyphCacheInfo *gcinfo;
225
226
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_AddToGlyphCache");
227
228
if (pixelFormat == GL_LUMINANCE) {
229
gcinfo = glyphCacheAA;
230
} else {
231
gcinfo = glyphCacheLCD;
232
}
233
234
if ((gcinfo == NULL) || (glyph->image == NULL)) {
235
return;
236
}
237
238
AccelGlyphCache_AddGlyph(gcinfo, glyph);
239
ccinfo = (CacheCellInfo *) glyph->cellInfo;
240
241
if (ccinfo != NULL) {
242
// store glyph image in texture cell
243
j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
244
ccinfo->x, ccinfo->y,
245
glyph->width, glyph->height,
246
pixelFormat, GL_UNSIGNED_BYTE, glyph->image);
247
}
248
}
249
250
/**
251
* This is the GLSL fragment shader source code for rendering LCD-optimized
252
* text. Do not be frightened; it is much easier to understand than the
253
* equivalent ASM-like fragment program!
254
*
255
* The "uniform" variables at the top are initialized once the program is
256
* linked, and are updated at runtime as needed (e.g. when the source color
257
* changes, we will modify the "src_adj" value in OGLTR_UpdateLCDTextColor()).
258
*
259
* The "main" function is executed for each "fragment" (or pixel) in the
260
* glyph image. The pow() routine operates on vectors, gives precise results,
261
* and provides acceptable level of performance, so we use it to perform
262
* the gamma adjustment.
263
*
264
* The variables involved in the equation can be expressed as follows:
265
*
266
* Cs = Color component of the source (foreground color) [0.0, 1.0]
267
* Cd = Color component of the destination (background color) [0.0, 1.0]
268
* Cr = Color component to be written to the destination [0.0, 1.0]
269
* Ag = Glyph alpha (aka intensity or coverage) [0.0, 1.0]
270
* Ga = Gamma adjustment in the range [1.0, 2.5]
271
* (^ means raised to the power)
272
*
273
* And here is the theoretical equation approximated by this shader:
274
*
275
* Cr = (Ag*(Cs^Ga) + (1-Ag)*(Cd^Ga)) ^ (1/Ga)
276
*/
277
static const char *lcdTextShaderSource =
278
"uniform vec3 src_adj;"
279
"uniform sampler2D glyph_tex;"
280
"uniform sampler2D dst_tex;"
281
"uniform vec3 gamma;"
282
"uniform vec3 invgamma;"
283
""
284
"void main(void)"
285
"{"
286
// load the RGB value from the glyph image at the current texcoord
287
" vec3 glyph_clr = vec3(texture2D(glyph_tex, gl_TexCoord[0].st));"
288
" if (glyph_clr == vec3(0.0)) {"
289
// zero coverage, so skip this fragment
290
" discard;"
291
" }"
292
// load the RGB value from the corresponding destination pixel
293
" vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));"
294
// gamma adjust the dest color
295
" vec3 dst_adj = pow(dst_clr.rgb, gamma);"
296
// linearly interpolate the three color values
297
" vec3 result = mix(dst_adj, src_adj, glyph_clr);"
298
// gamma re-adjust the resulting color (alpha is always set to 1.0)
299
" gl_FragColor = vec4(pow(result.rgb, invgamma), 1.0);"
300
"}";
301
302
/**
303
* Compiles and links the LCD text shader program. If successful, this
304
* function returns a handle to the newly created shader program; otherwise
305
* returns 0.
306
*/
307
static GLhandleARB
308
OGLTR_CreateLCDTextProgram()
309
{
310
GLhandleARB lcdTextProgram;
311
GLint loc;
312
313
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_CreateLCDTextProgram");
314
315
lcdTextProgram = OGLContext_CreateFragmentProgram(lcdTextShaderSource);
316
if (lcdTextProgram == 0) {
317
J2dRlsTraceLn(J2D_TRACE_ERROR,
318
"OGLTR_CreateLCDTextProgram: error creating program");
319
return 0;
320
}
321
322
// "use" the program object temporarily so that we can set the uniforms
323
j2d_glUseProgramObjectARB(lcdTextProgram);
324
325
// set the "uniform" values
326
loc = j2d_glGetUniformLocationARB(lcdTextProgram, "glyph_tex");
327
j2d_glUniform1iARB(loc, 0); // texture unit 0
328
loc = j2d_glGetUniformLocationARB(lcdTextProgram, "dst_tex");
329
j2d_glUniform1iARB(loc, 1); // texture unit 1
330
331
// "unuse" the program object; it will be re-bound later as needed
332
j2d_glUseProgramObjectARB(0);
333
334
return lcdTextProgram;
335
}
336
337
/**
338
* (Re)Initializes the gamma related uniforms.
339
*
340
* The given contrast value is an int in the range [100, 250] which we will
341
* then scale to fit in the range [1.0, 2.5].
342
*/
343
static jboolean
344
OGLTR_UpdateLCDTextContrast(jint contrast)
345
{
346
double g = ((double)contrast) / 100.0;
347
double ig = 1.0 / g;
348
GLint loc;
349
350
J2dTraceLn1(J2D_TRACE_INFO,
351
"OGLTR_UpdateLCDTextContrast: contrast=%d", contrast);
352
353
loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma");
354
j2d_glUniform3fARB(loc, g, g, g);
355
356
loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma");
357
j2d_glUniform3fARB(loc, ig, ig, ig);
358
359
return JNI_TRUE;
360
}
361
362
/**
363
* Updates the current gamma-adjusted source color ("src_adj") of the LCD
364
* text shader program. Note that we could calculate this value in the
365
* shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
366
* (and a measurable performance hit, maybe around 5%) since this value is
367
* constant over the entire glyph list. So instead we just calculate the
368
* gamma-adjusted value once and update the uniform parameter of the LCD
369
* shader as needed.
370
*/
371
static jboolean
372
OGLTR_UpdateLCDTextColor(jint contrast)
373
{
374
double gamma = ((double)contrast) / 100.0;
375
GLfloat radj, gadj, badj;
376
GLfloat clr[4];
377
GLint loc;
378
379
J2dTraceLn1(J2D_TRACE_INFO,
380
"OGLTR_UpdateLCDTextColor: contrast=%d", contrast);
381
382
/*
383
* Note: Ideally we would update the "src_adj" uniform parameter only
384
* when there is a change in the source color. Fortunately, the cost
385
* of querying the current OpenGL color state and updating the uniform
386
* value is quite small, and in the common case we only need to do this
387
* once per GlyphList, so we gain little from trying to optimize too
388
* eagerly here.
389
*/
390
391
// get the current OpenGL primary color state
392
j2d_glGetFloatv(GL_CURRENT_COLOR, clr);
393
394
// gamma adjust the primary color
395
radj = (GLfloat)pow(clr[0], gamma);
396
gadj = (GLfloat)pow(clr[1], gamma);
397
badj = (GLfloat)pow(clr[2], gamma);
398
399
// update the "src_adj" parameter of the shader program with this value
400
loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");
401
j2d_glUniform3fARB(loc, radj, gadj, badj);
402
403
return JNI_TRUE;
404
}
405
406
/**
407
* Enables the LCD text shader and updates any related state, such as the
408
* gamma lookup table textures.
409
*/
410
static jboolean
411
OGLTR_EnableLCDGlyphModeState(GLuint glyphTextureID,
412
GLuint dstTextureID,
413
jint contrast)
414
{
415
// bind the texture containing glyph data to texture unit 0
416
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
417
j2d_glBindTexture(GL_TEXTURE_2D, glyphTextureID);
418
j2d_glEnable(GL_TEXTURE_2D);
419
420
// bind the texture tile containing destination data to texture unit 1
421
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
422
if (dstTextureID != 0) {
423
j2d_glBindTexture(GL_TEXTURE_2D, dstTextureID);
424
} else {
425
if (cachedDestTextureID == 0) {
426
cachedDestTextureID =
427
OGLContext_CreateBlitTexture(GL_RGB8, GL_RGB,
428
OGLTR_CACHED_DEST_WIDTH,
429
OGLTR_CACHED_DEST_HEIGHT);
430
if (cachedDestTextureID == 0) {
431
return JNI_FALSE;
432
}
433
}
434
j2d_glBindTexture(GL_TEXTURE_2D, cachedDestTextureID);
435
}
436
437
// note that GL_TEXTURE_2D was already enabled for texture unit 0,
438
// but we need to explicitly enable it for texture unit 1
439
j2d_glEnable(GL_TEXTURE_2D);
440
441
// create the LCD text shader, if necessary
442
if (lcdTextProgram == 0) {
443
lcdTextProgram = OGLTR_CreateLCDTextProgram();
444
if (lcdTextProgram == 0) {
445
return JNI_FALSE;
446
}
447
}
448
449
// enable the LCD text shader
450
j2d_glUseProgramObjectARB(lcdTextProgram);
451
452
// update the current contrast settings, if necessary
453
if (lastLCDContrast != contrast) {
454
if (!OGLTR_UpdateLCDTextContrast(contrast)) {
455
return JNI_FALSE;
456
}
457
lastLCDContrast = contrast;
458
}
459
460
// update the current color settings
461
if (!OGLTR_UpdateLCDTextColor(contrast)) {
462
return JNI_FALSE;
463
}
464
465
return JNI_TRUE;
466
}
467
468
void
469
OGLTR_EnableGlyphVertexCache(OGLContext *oglc)
470
{
471
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_EnableGlyphVertexCache");
472
473
if (!OGLVertexCache_InitVertexCache(oglc)) {
474
return;
475
}
476
477
if (glyphCacheAA == NULL) {
478
if (!OGLTR_InitGlyphCache(JNI_FALSE)) {
479
return;
480
}
481
}
482
483
j2d_glEnable(GL_TEXTURE_2D);
484
j2d_glBindTexture(GL_TEXTURE_2D, glyphCacheAA->cacheID);
485
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
486
487
// for grayscale/monochrome text, the current OpenGL source color
488
// is modulated with the glyph image as part of the texture
489
// application stage, so we use GL_MODULATE here
490
OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
491
}
492
493
void
494
OGLTR_DisableGlyphVertexCache(OGLContext *oglc)
495
{
496
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DisableGlyphVertexCache");
497
498
OGLVertexCache_FlushVertexCache();
499
OGLVertexCache_RestoreColorState(oglc);
500
501
j2d_glDisable(GL_TEXTURE_2D);
502
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
503
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
504
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
505
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
506
}
507
508
/**
509
* Disables any pending state associated with the current "glyph mode".
510
*/
511
static void
512
OGLTR_DisableGlyphModeState()
513
{
514
switch (glyphMode) {
515
case MODE_NO_CACHE_LCD:
516
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
517
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
518
/* FALLTHROUGH */
519
520
case MODE_USE_CACHE_LCD:
521
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
522
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
523
j2d_glUseProgramObjectARB(0);
524
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
525
j2d_glDisable(GL_TEXTURE_2D);
526
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
527
j2d_glDisable(GL_TEXTURE_2D);
528
break;
529
530
case MODE_NO_CACHE_COLOR:
531
case MODE_NO_CACHE_GRAY:
532
case MODE_USE_CACHE_GRAY:
533
case MODE_NOT_INITED:
534
default:
535
break;
536
}
537
}
538
539
static jboolean
540
OGLTR_DrawGrayscaleGlyphViaCache(OGLContext *oglc,
541
GlyphInfo *ginfo, jint x, jint y)
542
{
543
CacheCellInfo *cell;
544
jfloat x1, y1, x2, y2;
545
546
if (glyphMode != MODE_USE_CACHE_GRAY) {
547
OGLTR_DisableGlyphModeState();
548
CHECK_PREVIOUS_OP(OGL_STATE_GLYPH_OP);
549
glyphMode = MODE_USE_CACHE_GRAY;
550
}
551
552
if (ginfo->cellInfo == NULL) {
553
// attempt to add glyph to accelerated glyph cache
554
OGLTR_AddToGlyphCache(ginfo, GL_LUMINANCE);
555
556
if (ginfo->cellInfo == NULL) {
557
// we'll just no-op in the rare case that the cell is NULL
558
return JNI_TRUE;
559
}
560
}
561
562
cell = (CacheCellInfo *) (ginfo->cellInfo);
563
cell->timesRendered++;
564
565
x1 = (jfloat)x;
566
y1 = (jfloat)y;
567
x2 = x1 + ginfo->width;
568
y2 = y1 + ginfo->height;
569
570
OGLVertexCache_AddGlyphQuad(oglc,
571
cell->tx1, cell->ty1,
572
cell->tx2, cell->ty2,
573
x1, y1, x2, y2);
574
575
return JNI_TRUE;
576
}
577
578
/**
579
* Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 is
580
* inside outerBounds.
581
*/
582
#define INSIDE(gx1, gy1, gx2, gy2, outerBounds) \
583
(((gx1) >= outerBounds.x1) && ((gy1) >= outerBounds.y1) && \
584
((gx2) <= outerBounds.x2) && ((gy2) <= outerBounds.y2))
585
586
/**
587
* Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 intersects
588
* the rectangle defined by bounds.
589
*/
590
#define INTERSECTS(gx1, gy1, gx2, gy2, bounds) \
591
((bounds.x2 > (gx1)) && (bounds.y2 > (gy1)) && \
592
(bounds.x1 < (gx2)) && (bounds.y1 < (gy2)))
593
594
/**
595
* This method checks to see if the given LCD glyph bounds fall within the
596
* cached destination texture bounds. If so, this method can return
597
* immediately. If not, this method will copy a chunk of framebuffer data
598
* into the cached destination texture and then update the current cached
599
* destination bounds before returning.
600
*/
601
static void
602
OGLTR_UpdateCachedDestination(OGLSDOps *dstOps, GlyphInfo *ginfo,
603
jint gx1, jint gy1, jint gx2, jint gy2,
604
jint glyphIndex, jint totalGlyphs)
605
{
606
jint dx1, dy1, dx2, dy2;
607
jint dx1adj, dy1adj;
608
609
if (isCachedDestValid && INSIDE(gx1, gy1, gx2, gy2, cachedDestBounds)) {
610
// glyph is already within the cached destination bounds; no need
611
// to read back the entire destination region again, but we do
612
// need to see if the current glyph overlaps the previous glyph...
613
614
if (INTERSECTS(gx1, gy1, gx2, gy2, previousGlyphBounds)) {
615
// the current glyph overlaps the destination region touched
616
// by the previous glyph, so now we need to read back the part
617
// of the destination corresponding to the previous glyph
618
dx1 = previousGlyphBounds.x1;
619
dy1 = previousGlyphBounds.y1;
620
dx2 = previousGlyphBounds.x2;
621
dy2 = previousGlyphBounds.y2;
622
623
// this accounts for lower-left origin of the destination region
624
dx1adj = dstOps->xOffset + dx1;
625
dy1adj = dstOps->yOffset + dstOps->height - dy2;
626
627
// copy destination into subregion of cached texture tile:
628
// dx1-cachedDestBounds.x1 == +xoffset from left side of texture
629
// cachedDestBounds.y2-dy2 == +yoffset from bottom of texture
630
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
631
j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
632
dx1 - cachedDestBounds.x1,
633
cachedDestBounds.y2 - dy2,
634
dx1adj, dy1adj,
635
dx2-dx1, dy2-dy1);
636
}
637
} else {
638
jint remainingWidth;
639
640
// destination region is not valid, so we need to read back a
641
// chunk of the destination into our cached texture
642
643
// position the upper-left corner of the destination region on the
644
// "top" line of glyph list
645
// REMIND: this isn't ideal; it would be better if we had some idea
646
// of the bounding box of the whole glyph list (this is
647
// do-able, but would require iterating through the whole
648
// list up front, which may present its own problems)
649
dx1 = gx1;
650
dy1 = gy1;
651
652
if (ginfo->advanceX > 0) {
653
// estimate the width based on our current position in the glyph
654
// list and using the x advance of the current glyph (this is just
655
// a quick and dirty heuristic; if this is a "thin" glyph image,
656
// then we're likely to underestimate, and if it's "thick" then we
657
// may end up reading back more than we need to)
658
remainingWidth =
659
(jint)(ginfo->advanceX * (totalGlyphs - glyphIndex));
660
if (remainingWidth > OGLTR_CACHED_DEST_WIDTH) {
661
remainingWidth = OGLTR_CACHED_DEST_WIDTH;
662
} else if (remainingWidth < ginfo->width) {
663
// in some cases, the x-advance may be slightly smaller
664
// than the actual width of the glyph; if so, adjust our
665
// estimate so that we can accommodate the entire glyph
666
remainingWidth = ginfo->width;
667
}
668
} else {
669
// a negative advance is possible when rendering rotated text,
670
// in which case it is difficult to estimate an appropriate
671
// region for readback, so we will pick a region that
672
// encompasses just the current glyph
673
remainingWidth = ginfo->width;
674
}
675
dx2 = dx1 + remainingWidth;
676
677
// estimate the height (this is another sloppy heuristic; we'll
678
// make the cached destination region tall enough to encompass most
679
// glyphs that are small enough to fit in the glyph cache, and then
680
// we add a little something extra to account for descenders
681
dy2 = dy1 + OGLTR_CACHE_CELL_HEIGHT + 2;
682
683
// this accounts for lower-left origin of the destination region
684
dx1adj = dstOps->xOffset + dx1;
685
dy1adj = dstOps->yOffset + dstOps->height - dy2;
686
687
// copy destination into cached texture tile (the lower-left corner
688
// of the destination region will be positioned at the lower-left
689
// corner (0,0) of the texture)
690
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
691
j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
692
0, 0, dx1adj, dy1adj,
693
dx2-dx1, dy2-dy1);
694
695
// update the cached bounds and mark it valid
696
cachedDestBounds.x1 = dx1;
697
cachedDestBounds.y1 = dy1;
698
cachedDestBounds.x2 = dx2;
699
cachedDestBounds.y2 = dy2;
700
isCachedDestValid = JNI_TRUE;
701
}
702
703
// always update the previous glyph bounds
704
previousGlyphBounds.x1 = gx1;
705
previousGlyphBounds.y1 = gy1;
706
previousGlyphBounds.x2 = gx2;
707
previousGlyphBounds.y2 = gy2;
708
}
709
710
static jboolean
711
OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
712
GlyphInfo *ginfo, jint x, jint y,
713
jint glyphIndex, jint totalGlyphs,
714
jboolean rgbOrder, jint contrast,
715
GLuint dstTextureID)
716
{
717
CacheCellInfo *cell;
718
jint dx1, dy1, dx2, dy2;
719
jfloat dtx1, dty1, dtx2, dty2;
720
721
if (glyphMode != MODE_USE_CACHE_LCD) {
722
OGLTR_DisableGlyphModeState();
723
CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
724
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
725
726
if (glyphCacheLCD == NULL) {
727
if (!OGLTR_InitGlyphCache(JNI_TRUE)) {
728
return JNI_FALSE;
729
}
730
}
731
732
if (rgbOrder != lastRGBOrder) {
733
// need to invalidate the cache in this case; see comments
734
// for lastRGBOrder above
735
AccelGlyphCache_Invalidate(glyphCacheLCD);
736
lastRGBOrder = rgbOrder;
737
}
738
739
if (!OGLTR_EnableLCDGlyphModeState(glyphCacheLCD->cacheID,
740
dstTextureID, contrast))
741
{
742
return JNI_FALSE;
743
}
744
745
// when a fragment shader is enabled, the texture function state is
746
// ignored, so the following line is not needed...
747
// OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
748
749
glyphMode = MODE_USE_CACHE_LCD;
750
}
751
752
if (ginfo->cellInfo == NULL) {
753
// rowBytes will always be a multiple of 3, so the following is safe
754
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
755
756
// make sure the glyph cache texture is bound to texture unit 0
757
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
758
759
// attempt to add glyph to accelerated glyph cache
760
OGLTR_AddToGlyphCache(ginfo, rgbOrder ? GL_RGB : GL_BGR);
761
762
if (ginfo->cellInfo == NULL) {
763
// we'll just no-op in the rare case that the cell is NULL
764
return JNI_TRUE;
765
}
766
}
767
768
cell = (CacheCellInfo *) (ginfo->cellInfo);
769
cell->timesRendered++;
770
771
// location of the glyph in the destination's coordinate space
772
dx1 = x;
773
dy1 = y;
774
dx2 = dx1 + ginfo->width;
775
dy2 = dy1 + ginfo->height;
776
777
if (dstTextureID == 0) {
778
// copy destination into second cached texture, if necessary
779
OGLTR_UpdateCachedDestination(dstOps, ginfo,
780
dx1, dy1, dx2, dy2,
781
glyphIndex, totalGlyphs);
782
783
// texture coordinates of the destination tile
784
dtx1 = ((jfloat)(dx1 - cachedDestBounds.x1)) / OGLTR_CACHED_DEST_WIDTH;
785
dty1 = ((jfloat)(cachedDestBounds.y2 - dy1)) / OGLTR_CACHED_DEST_HEIGHT;
786
dtx2 = ((jfloat)(dx2 - cachedDestBounds.x1)) / OGLTR_CACHED_DEST_WIDTH;
787
dty2 = ((jfloat)(cachedDestBounds.y2 - dy2)) / OGLTR_CACHED_DEST_HEIGHT;
788
} else {
789
jint gw = ginfo->width;
790
jint gh = ginfo->height;
791
792
// this accounts for lower-left origin of the destination region
793
jint dxadj = dstOps->xOffset + x;
794
jint dyadj = dstOps->yOffset + dstOps->height - (y + gh);
795
796
// update the remaining destination texture coordinates
797
dtx1 =((GLfloat)dxadj) / dstOps->textureWidth;
798
dtx2 = ((GLfloat)dxadj + gw) / dstOps->textureWidth;
799
800
dty1 = ((GLfloat)dyadj + gh) / dstOps->textureHeight;
801
dty2 = ((GLfloat)dyadj) / dstOps->textureHeight;
802
803
j2d_glTextureBarrierNV();
804
}
805
806
// render composed texture to the destination surface
807
j2d_glBegin(GL_QUADS);
808
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty1);
809
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
810
j2d_glVertex2i(dx1, dy1);
811
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty1);
812
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
813
j2d_glVertex2i(dx2, dy1);
814
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty2);
815
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
816
j2d_glVertex2i(dx2, dy2);
817
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty2);
818
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
819
j2d_glVertex2i(dx1, dy2);
820
j2d_glEnd();
821
822
return JNI_TRUE;
823
}
824
825
static jboolean
826
OGLTR_DrawGrayscaleGlyphNoCache(OGLContext *oglc,
827
GlyphInfo *ginfo, jint x, jint y)
828
{
829
jint tw, th;
830
jint sx, sy, sw, sh;
831
jint x0;
832
jint w = ginfo->width;
833
jint h = ginfo->height;
834
835
if (glyphMode != MODE_NO_CACHE_GRAY) {
836
OGLTR_DisableGlyphModeState();
837
CHECK_PREVIOUS_OP(OGL_STATE_MASK_OP);
838
glyphMode = MODE_NO_CACHE_GRAY;
839
}
840
841
x0 = x;
842
tw = OGLVC_MASK_CACHE_TILE_WIDTH;
843
th = OGLVC_MASK_CACHE_TILE_HEIGHT;
844
845
for (sy = 0; sy < h; sy += th, y += th) {
846
x = x0;
847
sh = ((sy + th) > h) ? (h - sy) : th;
848
849
for (sx = 0; sx < w; sx += tw, x += tw) {
850
sw = ((sx + tw) > w) ? (w - sx) : tw;
851
852
OGLVertexCache_AddMaskQuad(oglc,
853
sx, sy, x, y, sw, sh,
854
w, ginfo->image);
855
}
856
}
857
858
return JNI_TRUE;
859
}
860
861
static jboolean
862
OGLTR_DrawLCDGlyphNoCache(OGLContext *oglc, OGLSDOps *dstOps,
863
GlyphInfo *ginfo, jint x, jint y,
864
jint rowBytesOffset,
865
jboolean rgbOrder, jint contrast,
866
GLuint dstTextureID)
867
{
868
GLfloat tx1, ty1, tx2, ty2;
869
GLfloat dtx1, dty1, dtx2, dty2;
870
jint tw, th;
871
jint sx, sy, sw, sh, dxadj, dyadj;
872
jint x0;
873
jint w = ginfo->width;
874
jint h = ginfo->height;
875
GLenum pixelFormat = rgbOrder ? GL_RGB : GL_BGR;
876
877
if (glyphMode != MODE_NO_CACHE_LCD) {
878
OGLTR_DisableGlyphModeState();
879
CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
880
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
881
882
if (oglc->blitTextureID == 0) {
883
if (!OGLContext_InitBlitTileTexture(oglc)) {
884
return JNI_FALSE;
885
}
886
}
887
888
if (!OGLTR_EnableLCDGlyphModeState(oglc->blitTextureID,
889
dstTextureID, contrast))
890
{
891
return JNI_FALSE;
892
}
893
894
// when a fragment shader is enabled, the texture function state is
895
// ignored, so the following line is not needed...
896
// OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
897
898
glyphMode = MODE_NO_CACHE_LCD;
899
}
900
901
// rowBytes will always be a multiple of 3, so the following is safe
902
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
903
904
x0 = x;
905
tx1 = 0.0f;
906
ty1 = 0.0f;
907
dtx1 = 0.0f;
908
dty2 = 0.0f;
909
tw = OGLTR_NOCACHE_TILE_SIZE;
910
th = OGLTR_NOCACHE_TILE_SIZE;
911
912
for (sy = 0; sy < h; sy += th, y += th) {
913
x = x0;
914
sh = ((sy + th) > h) ? (h - sy) : th;
915
916
for (sx = 0; sx < w; sx += tw, x += tw) {
917
sw = ((sx + tw) > w) ? (w - sx) : tw;
918
919
// update the source pointer offsets
920
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
921
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
922
923
// copy LCD mask into glyph texture tile
924
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
925
j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
926
0, 0, sw, sh,
927
pixelFormat, GL_UNSIGNED_BYTE,
928
ginfo->image + rowBytesOffset);
929
930
// update the lower-right glyph texture coordinates
931
tx2 = ((GLfloat)sw) / OGLC_BLIT_TILE_SIZE;
932
ty2 = ((GLfloat)sh) / OGLC_BLIT_TILE_SIZE;
933
934
// this accounts for lower-left origin of the destination region
935
dxadj = dstOps->xOffset + x;
936
dyadj = dstOps->yOffset + dstOps->height - (y + sh);
937
938
if (dstTextureID == 0) {
939
// copy destination into cached texture tile (the lower-left
940
// corner of the destination region will be positioned at the
941
// lower-left corner (0,0) of the texture)
942
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
943
j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
944
0, 0,
945
dxadj, dyadj,
946
sw, sh);
947
// update the remaining destination texture coordinates
948
dtx2 = ((GLfloat)sw) / OGLTR_CACHED_DEST_WIDTH;
949
dty1 = ((GLfloat)sh) / OGLTR_CACHED_DEST_HEIGHT;
950
} else {
951
// use the destination texture directly
952
// update the remaining destination texture coordinates
953
dtx1 =((GLfloat)dxadj) / dstOps->textureWidth;
954
dtx2 = ((GLfloat)dxadj + sw) / dstOps->textureWidth;
955
956
dty1 = ((GLfloat)dyadj + sh) / dstOps->textureHeight;
957
dty2 = ((GLfloat)dyadj) / dstOps->textureHeight;
958
959
j2d_glTextureBarrierNV();
960
}
961
962
// render composed texture to the destination surface
963
j2d_glBegin(GL_QUADS);
964
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty1);
965
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
966
j2d_glVertex2i(x, y);
967
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty1);
968
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
969
j2d_glVertex2i(x + sw, y);
970
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx2, ty2);
971
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
972
j2d_glVertex2i(x + sw, y + sh);
973
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tx1, ty2);
974
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
975
j2d_glVertex2i(x, y + sh);
976
j2d_glEnd();
977
}
978
}
979
980
return JNI_TRUE;
981
}
982
983
static jboolean
984
OGLTR_DrawColorGlyphNoCache(OGLContext *oglc, GlyphInfo *ginfo, jint x, jint y)
985
{
986
if (glyphMode != MODE_NO_CACHE_COLOR) {
987
OGLTR_DisableGlyphModeState();
988
RESET_PREVIOUS_OP();
989
glyphMode = MODE_NO_CACHE_COLOR;
990
}
991
992
// see OGLBlitSwToSurface() in OGLBlitLoops.c
993
// for more info on the following two lines
994
j2d_glRasterPos2i(0, 0);
995
j2d_glBitmap(0, 0, 0, 0, (GLfloat) x, (GLfloat) (-y), NULL);
996
997
// in OpenGL image data is assumed to contain lines from bottom to top
998
j2d_glPixelZoom(1, -1);
999
1000
j2d_glDrawPixels(ginfo->width, ginfo->height, GL_BGRA, GL_UNSIGNED_BYTE,
1001
ginfo->image);
1002
1003
// restoring state
1004
j2d_glPixelZoom(1, 1);
1005
1006
return JNI_TRUE;
1007
}
1008
1009
1010
// see DrawGlyphList.c for more on this macro...
1011
#define FLOOR_ASSIGN(l, r) \
1012
if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
1013
1014
void
1015
OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
1016
jint totalGlyphs, jboolean usePositions,
1017
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
1018
jfloat glyphListOrigX, jfloat glyphListOrigY,
1019
unsigned char *images, unsigned char *positions)
1020
{
1021
int glyphCounter;
1022
GLuint dstTextureID = 0;
1023
1024
J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
1025
1026
RETURN_IF_NULL(oglc);
1027
RETURN_IF_NULL(dstOps);
1028
RETURN_IF_NULL(images);
1029
if (usePositions) {
1030
RETURN_IF_NULL(positions);
1031
}
1032
1033
glyphMode = MODE_NOT_INITED;
1034
isCachedDestValid = JNI_FALSE;
1035
1036
// We have to obtain an information about destination content
1037
// in order to render lcd glyphs. It could be done by copying
1038
// a part of desitination buffer into an intermediate texture
1039
// using glCopyTexSubImage2D(). However, on macosx this path is
1040
// slow, and it dramatically reduces the overall speed of lcd
1041
// text rendering.
1042
//
1043
// In some cases, we can use a texture from the destination
1044
// surface data in oredr to avoid this slow reading routine.
1045
// It requires:
1046
// * An appropriate textureTarget for the destination SD.
1047
// In particular, we need GL_TEXTURE_2D
1048
// * Means to prevent read-after-write problem.
1049
// At the moment, a GL_NV_texture_barrier extension is used
1050
// to achieve this.
1051
if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_TEXBARRIER) &&
1052
dstOps->textureTarget == GL_TEXTURE_2D)
1053
{
1054
dstTextureID = dstOps->textureID;
1055
}
1056
1057
for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
1058
jint x, y;
1059
jfloat glyphx, glyphy;
1060
jboolean ok;
1061
GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
1062
1063
if (ginfo == NULL) {
1064
// this shouldn't happen, but if it does we'll just break out...
1065
J2dRlsTraceLn(J2D_TRACE_ERROR,
1066
"OGLTR_DrawGlyphList: glyph info is null");
1067
break;
1068
}
1069
1070
if (usePositions) {
1071
jfloat posx = NEXT_FLOAT(positions);
1072
jfloat posy = NEXT_FLOAT(positions);
1073
glyphx = glyphListOrigX + posx + ginfo->topLeftX;
1074
glyphy = glyphListOrigY + posy + ginfo->topLeftY;
1075
FLOOR_ASSIGN(x, glyphx);
1076
FLOOR_ASSIGN(y, glyphy);
1077
} else {
1078
glyphx = glyphListOrigX + ginfo->topLeftX;
1079
glyphy = glyphListOrigY + ginfo->topLeftY;
1080
FLOOR_ASSIGN(x, glyphx);
1081
FLOOR_ASSIGN(y, glyphy);
1082
glyphListOrigX += ginfo->advanceX;
1083
glyphListOrigY += ginfo->advanceY;
1084
}
1085
1086
if (ginfo->image == NULL) {
1087
continue;
1088
}
1089
1090
if (ginfo->rowBytes == ginfo->width) {
1091
// grayscale or monochrome glyph data
1092
if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
1093
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
1094
{
1095
ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y);
1096
} else {
1097
ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
1098
}
1099
} else if (ginfo->rowBytes == ginfo->width * 4) {
1100
// color glyph data
1101
ok = OGLTR_DrawColorGlyphNoCache(oglc, ginfo, x, y);
1102
} else {
1103
// LCD-optimized glyph data
1104
jint rowBytesOffset = 0;
1105
1106
if (subPixPos) {
1107
jint frac = (jint)((glyphx - x) * 3);
1108
if (frac != 0) {
1109
rowBytesOffset = 3 - frac;
1110
x += 1;
1111
}
1112
}
1113
1114
if (rowBytesOffset == 0 &&
1115
ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
1116
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
1117
{
1118
ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps,
1119
ginfo, x, y,
1120
glyphCounter, totalGlyphs,
1121
rgbOrder, lcdContrast,
1122
dstTextureID);
1123
} else {
1124
ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
1125
ginfo, x, y,
1126
rowBytesOffset,
1127
rgbOrder, lcdContrast,
1128
dstTextureID);
1129
}
1130
}
1131
1132
if (!ok) {
1133
break;
1134
}
1135
}
1136
1137
OGLTR_DisableGlyphModeState();
1138
}
1139
1140
JNIEXPORT void JNICALL
1141
Java_sun_java2d_opengl_OGLTextRenderer_drawGlyphList
1142
(JNIEnv *env, jobject self,
1143
jint numGlyphs, jboolean usePositions,
1144
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
1145
jfloat glyphListOrigX, jfloat glyphListOrigY,
1146
jlongArray imgArray, jfloatArray posArray)
1147
{
1148
unsigned char *images;
1149
1150
J2dTraceLn(J2D_TRACE_INFO, "OGLTextRenderer_drawGlyphList");
1151
1152
images = (unsigned char *)
1153
(*env)->GetPrimitiveArrayCritical(env, imgArray, NULL);
1154
if (images != NULL) {
1155
OGLContext *oglc = OGLRenderQueue_GetCurrentContext();
1156
OGLSDOps *dstOps = OGLRenderQueue_GetCurrentDestination();
1157
1158
if (usePositions) {
1159
unsigned char *positions = (unsigned char *)
1160
(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
1161
if (positions != NULL) {
1162
OGLTR_DrawGlyphList(env, oglc, dstOps,
1163
numGlyphs, usePositions,
1164
subPixPos, rgbOrder, lcdContrast,
1165
glyphListOrigX, glyphListOrigY,
1166
images, positions);
1167
(*env)->ReleasePrimitiveArrayCritical(env, posArray,
1168
positions, JNI_ABORT);
1169
}
1170
} else {
1171
OGLTR_DrawGlyphList(env, oglc, dstOps,
1172
numGlyphs, usePositions,
1173
subPixPos, rgbOrder, lcdContrast,
1174
glyphListOrigX, glyphListOrigY,
1175
images, NULL);
1176
}
1177
1178
// 6358147: reset current state, and ensure rendering is
1179
// flushed to dest
1180
if (oglc != NULL) {
1181
RESET_PREVIOUS_OP();
1182
j2d_glFlush();
1183
}
1184
1185
(*env)->ReleasePrimitiveArrayCritical(env, imgArray,
1186
images, JNI_ABORT);
1187
}
1188
}
1189
1190
#endif /* !HEADLESS */
1191
1192