]> git.ipfire.org Git - thirdparty/cups.git/blob - pstoraster/gscrdp.c
f04803f0cf959401b0049470b4a0dad03bebddea
[thirdparty/cups.git] / pstoraster / gscrdp.c
1 /* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
2
3 This file is part of GNU Ghostscript.
4
5 GNU Ghostscript is distributed in the hope that it will be useful, but
6 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
7 to anyone for the consequences of using it or for whether it serves any
8 particular purpose or works at all, unless he says so in writing. Refer
9 to the GNU General Public License for full details.
10
11 Everyone is granted permission to copy, modify and redistribute GNU
12 Ghostscript, but only under the conditions described in the GNU General
13 Public License. A copy of this license is supposed to have been given
14 to you along with GNU Ghostscript so you can know your rights and
15 responsibilities. It should be in a file named COPYING. Among other
16 things, the copyright notice and this notice must be preserved on all
17 copies.
18
19 Aladdin Enterprises supports the work of the GNU Project, but is not
20 affiliated with the Free Software Foundation or the GNU Project. GNU
21 Ghostscript, as distributed by Aladdin Enterprises, does not require any
22 GNU software to build or run it.
23 */
24
25 /*$Id: gscrdp.c,v 1.2 2000/10/13 01:04:41 mike Exp $ */
26 /* CIE color rendering dictionary creation */
27 #include "math_.h"
28 #include "memory_.h"
29 #include "gx.h"
30 #include "gsdevice.h"
31 #include "gserrors.h"
32 #include "gsmatrix.h" /* for gscolor2.h */
33 #include "gxcspace.h"
34 #include "gscolor2.h" /* for gs_set/currentcolorrendering */
35 #include "gscrdp.h"
36 #include "gxarith.h"
37
38 /* Define the CRD type that we use here. */
39 #define CRD_TYPE 101
40
41 /* ---------------- Writing ---------------- */
42
43 /* Internal procedures for writing parameter values. */
44 private void
45 store_vector3(float *p, const gs_vector3 * pvec)
46 {
47 p[0] = pvec->u, p[1] = pvec->v, p[2] = pvec->w;
48 }
49 private int
50 write_floats(gs_param_list * plist, gs_param_name key,
51 const float *values, int size, gs_memory_t * mem)
52 {
53 float *p = (float *)
54 gs_alloc_byte_array(mem, size, sizeof(float), "write_floats");
55 gs_param_float_array fa;
56
57 if (p == 0)
58 return_error(gs_error_VMerror);
59 memcpy(p, values, size * sizeof(float));
60
61 fa.data = p;
62 fa.size = size;
63 fa.persistent = true;
64 return param_write_float_array(plist, key, &fa);
65 }
66 private int
67 write_vector3(gs_param_list * plist, gs_param_name key,
68 const gs_vector3 * pvec, gs_memory_t * mem)
69 {
70 float values[3];
71
72 store_vector3(values, pvec);
73 return write_floats(plist, key, values, 3, mem);
74 }
75 private int
76 write_matrix3(gs_param_list * plist, gs_param_name key,
77 const gs_matrix3 * pmat, gs_memory_t * mem)
78 {
79 float values[9];
80
81 if (!memcmp(pmat, &Matrix3_default, sizeof(*pmat)))
82 return 0;
83 store_vector3(values, &pmat->cu);
84 store_vector3(values + 3, &pmat->cv);
85 store_vector3(values + 6, &pmat->cw);
86 return write_floats(plist, key, values, 9, mem);
87 }
88 private int
89 write_range3(gs_param_list * plist, gs_param_name key,
90 const gs_range3 * prange, gs_memory_t * mem)
91 {
92 float values[6];
93
94 if (!memcmp(prange, &Range3_default, sizeof(*prange)))
95 return 0;
96 values[0] = prange->ranges[0].rmin, values[1] = prange->ranges[0].rmax;
97 values[2] = prange->ranges[1].rmin, values[3] = prange->ranges[1].rmax;
98 values[4] = prange->ranges[2].rmin, values[5] = prange->ranges[2].rmax;
99 return write_floats(plist, key, values, 6, mem);
100 }
101 private int
102 write_proc3(gs_param_list * plist, gs_param_name key,
103 const gs_cie_render * pcrd, const gs_cie_render_proc3 * procs,
104 const gs_range3 * domain, gs_memory_t * mem)
105 {
106 float *values;
107 uint size = gx_cie_cache_size;
108 gs_param_float_array fa;
109 int i;
110
111 if (!memcmp(procs, &Encode_default, sizeof(*procs)))
112 return 0;
113 values = (float *)gs_alloc_byte_array(mem, size * 3, sizeof(float),
114 "write_proc3");
115
116 if (values == 0)
117 return_error(gs_error_VMerror);
118 for (i = 0; i < 3; ++i) {
119 double base = domain->ranges[i].rmin;
120 double scale = (domain->ranges[i].rmax - base) / (size - 1);
121 int j;
122
123 for (j = 0; j < size; ++j)
124 values[i * size + j] =
125 (*procs->procs[i]) (j * scale + base, pcrd);
126 }
127 fa.data = values;
128 fa.size = size * 3;
129 fa.persistent = true;
130 return param_write_float_array(plist, key, &fa);
131 }
132
133 /* Write a CRD as a device parameter. */
134 int
135 param_write_cie_render1(gs_param_list * plist, gs_param_name key,
136 const gs_cie_render * pcrd, gs_memory_t * mem)
137 {
138 gs_param_dict dict;
139 int code, dcode;
140
141 dict.size = 20;
142 if ((code = param_begin_write_dict(plist, key, &dict, false)) < 0)
143 return code;
144 code = param_put_cie_render1(dict.list, pcrd, mem);
145 dcode = param_end_write_dict(plist, key, &dict);
146 return (code < 0 ? code : dcode);
147 }
148
149 /* Write a CRD directly to a parameter list. */
150 int
151 param_put_cie_render1(gs_param_list * plist, const gs_cie_render * pcrd,
152 gs_memory_t * mem)
153 {
154 int crd_type = CRD_TYPE;
155 int code;
156
157 if (pcrd->TransformPQR.proc_name) {
158 gs_param_string pn, pd;
159
160 param_string_from_string(pn, pcrd->TransformPQR.proc_name);
161 pn.size++; /* include terminating null */
162 pd.data = pcrd->TransformPQR.proc_data.data;
163 pd.size = pcrd->TransformPQR.proc_data.size;
164 pd.persistent = true; /****** WRONG ******/
165 if ((code = param_write_name(plist, "TransformPQRName", &pn)) < 0 ||
166 (code = param_write_string(plist, "TransformPQRData", &pd)) < 0
167 )
168 return code;
169 }
170 else if (pcrd->TransformPQR.proc != TransformPQR_default.proc) {
171 /* We have no way to represent the procedure, so return an error. */
172 return_error(gs_error_rangecheck);
173 }
174 if ((code = param_write_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
175 (code = write_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint, mem)) < 0
176 )
177 return code;
178 if (memcmp(&pcrd->points.BlackPoint, &BlackPoint_default,
179 sizeof(pcrd->points.BlackPoint))) {
180 if ((code = write_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint, mem)) < 0)
181 return code;
182 }
183 if ((code = write_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR, mem)) < 0 ||
184 (code = write_range3(plist, "RangePQR", &pcrd->RangePQR, mem)) < 0 ||
185 /* TransformPQR is handled separately */
186 (code = write_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN, mem)) < 0 ||
187 (code = write_proc3(plist, "EncodeLMNValues", pcrd,
188 &pcrd->EncodeLMN, &pcrd->DomainLMN, mem)) < 0 ||
189 (code = write_range3(plist, "RangeLMN", &pcrd->RangeLMN, mem)) < 0 ||
190 (code = write_matrix3(plist, "MatrixABC", &pcrd->MatrixABC, mem)) < 0 ||
191 (code = write_proc3(plist, "EncodeABCValues", pcrd,
192 &pcrd->EncodeABC, &pcrd->DomainABC, mem)) < 0 ||
193 (code = write_range3(plist, "RangeABC", &pcrd->RangeABC, mem)) < 0
194 )
195 return code;
196 if (pcrd->RenderTable.lookup.table) {
197 int n = pcrd->RenderTable.lookup.n;
198 int m = pcrd->RenderTable.lookup.m;
199 int na = pcrd->RenderTable.lookup.dims[0];
200 int *size = (int *)
201 gs_alloc_byte_array(mem, n + 1, sizeof(int), "RenderTableSize");
202
203 /*
204 * In principle, we should use gs_alloc_struct_array with a
205 * type descriptor for gs_param_string. However, it is widely
206 * assumed that parameter lists are transient, and don't require
207 * accurate GC information; so we can get away with allocating
208 * the string table as bytes.
209 */
210 gs_param_string *table =
211 (gs_param_string *)
212 gs_alloc_byte_array(mem, na, sizeof(gs_param_string),
213 "RenderTableTable");
214 gs_param_int_array ia;
215
216 if (size == 0 || table == 0)
217 code = gs_note_error(gs_error_VMerror);
218 else {
219 memcpy(size, pcrd->RenderTable.lookup.dims, sizeof(int) * n);
220
221 size[n] = m;
222 ia.data = size;
223 ia.size = n + 1;
224 ia.persistent = true;
225 code = param_write_int_array(plist, "RenderTableSize", &ia);
226 }
227 if (code >= 0) {
228 gs_param_string_array sa;
229 int a;
230
231 for (a = 0; a < na; ++a)
232 table[a].data = pcrd->RenderTable.lookup.table[a].data,
233 table[a].size = pcrd->RenderTable.lookup.table[a].size,
234 table[a].persistent = true;
235 sa.data = table;
236 sa.size = na;
237 sa.persistent = true;
238 code = param_write_string_array(plist, "RenderTableTable", &sa);
239 if (code >= 0 && !pcrd->caches.RenderTableT_is_identity) {
240 /****** WRITE RenderTableTValues LIKE write_proc3 ******/
241 uint size = gx_cie_cache_size;
242 float *values =
243 (float *)gs_alloc_byte_array(mem, size * m,
244 sizeof(float),
245 "write_proc3");
246 gs_param_float_array fa;
247 int i;
248
249 if (values == 0)
250 return_error(gs_error_VMerror);
251 for (i = 0; i < m; ++i) {
252 double scale = 255.0 / (size - 1);
253 int j;
254
255 for (j = 0; j < size; ++j)
256 values[i * size + j] =
257 frac2float((*pcrd->RenderTable.T.procs[i])
258 (j * scale, pcrd));
259 }
260 fa.data = values;
261 fa.size = size * m;
262 fa.persistent = true;
263 code = param_write_float_array(plist, "RenderTableTValues",
264 &fa);
265 }
266 }
267 if (code < 0) {
268 gs_free_object(mem, table, "RenderTableTable");
269 gs_free_object(mem, size, "RenderTableSize");
270 return code;
271 }
272 }
273 return code;
274 }
275
276 /* ---------------- Reading ---------------- */
277
278 /* Internal procedures for reading parameter values. */
279 private void
280 load_vector3(gs_vector3 * pvec, const float *p)
281 {
282 pvec->u = p[0], pvec->v = p[1], pvec->w = p[2];
283 }
284 private int
285 read_floats(gs_param_list * plist, gs_param_name key, float *values, int count)
286 {
287 gs_param_float_array fa;
288 int code = param_read_float_array(plist, key, &fa);
289
290 if (code)
291 return code;
292 if (fa.size != count)
293 return_error(gs_error_rangecheck);
294 memcpy(values, fa.data, sizeof(float) * count);
295
296 return 0;
297 }
298 private int
299 read_vector3(gs_param_list * plist, gs_param_name key,
300 gs_vector3 * pvec, const gs_vector3 * dflt)
301 {
302 float values[3];
303 int code = read_floats(plist, key, values, 3);
304
305 switch (code) {
306 case 1: /* not defined */
307 if (dflt)
308 *pvec = *dflt;
309 break;
310 case 0:
311 load_vector3(pvec, values);
312 default: /* error */
313 break;
314 }
315 return code;
316 }
317 private int
318 read_matrix3(gs_param_list * plist, gs_param_name key, gs_matrix3 * pmat)
319 {
320 float values[9];
321 int code = read_floats(plist, key, values, 9);
322
323 switch (code) {
324 case 1: /* not defined */
325 *pmat = Matrix3_default;
326 break;
327 case 0:
328 load_vector3(&pmat->cu, values);
329 load_vector3(&pmat->cv, values + 3);
330 load_vector3(&pmat->cw, values + 6);
331 default: /* error */
332 break;
333 }
334 return code;
335 }
336 private int
337 read_range3(gs_param_list * plist, gs_param_name key, gs_range3 * prange)
338 {
339 float values[6];
340 int code = read_floats(plist, key, values, 6);
341
342 switch (code) {
343 case 1: /* not defined */
344 *prange = Range3_default;
345 break;
346 case 0:
347 prange->ranges[0].rmin = values[0];
348 prange->ranges[0].rmax = values[1];
349 prange->ranges[1].rmin = values[2];
350 prange->ranges[1].rmax = values[3];
351 prange->ranges[2].rmin = values[4];
352 prange->ranges[2].rmax = values[5];
353 default: /* error */
354 break;
355 }
356 return code;
357 }
358 private int
359 read_proc3(gs_param_list * plist, gs_param_name key,
360 float values[gx_cie_cache_size * 3])
361 {
362 return read_floats(plist, key, values, gx_cie_cache_size * 3);
363 }
364
365 /* Read a CRD from a device parameter. */
366 int
367 gs_cie_render1_param_initialize(gs_cie_render * pcrd, gs_param_list * plist,
368 gs_param_name key, gx_device * dev)
369 {
370 gs_param_dict dict;
371 int code = param_begin_read_dict(plist, key, &dict, false);
372 int dcode;
373
374 if (code < 0)
375 return code;
376 code = param_get_cie_render1(pcrd, dict.list, dev);
377 dcode = param_end_read_dict(plist, key, &dict);
378 if (code < 0)
379 return code;
380 if (dcode < 0)
381 return dcode;
382 gs_cie_render_init(pcrd);
383 gs_cie_render_sample(pcrd);
384 return gs_cie_render_complete(pcrd);
385 }
386
387 /* Define the structure for passing Encode values as "client data". */
388 typedef struct encode_data_s {
389 float lmn[gx_cie_cache_size * 3]; /* EncodeLMN */
390 float abc[gx_cie_cache_size * 3]; /* EncodeABC */
391 float t[gx_cie_cache_size * 4]; /* RenderTable.T */
392 } encode_data_t;
393
394 /* Define procedures that retrieve the Encode values read from the list. */
395 private float
396 encode_from_data(floatp v, const float values[gx_cie_cache_size],
397 const gs_range * range)
398 {
399 return (v <= range->rmin ? values[0] :
400 v >= range->rmax ? values[gx_cie_cache_size - 1] :
401 values[(int)((v - range->rmin) / (range->rmax - range->rmin) *
402 (gx_cie_cache_size - 1) + 0.5)]);
403 }
404 /*
405 * The repetitive boilerplate in the next 10 procedures really sticks in
406 * my craw, but I've got a mandate not to use macros....
407 */
408 private float
409 encode_lmn_0_from_data(floatp v, const gs_cie_render * pcrd)
410 {
411 const encode_data_t *data = pcrd->client_data;
412
413 return encode_from_data(v, &data->lmn[0],
414 &pcrd->DomainLMN.ranges[0]);
415 }
416 private float
417 encode_lmn_1_from_data(floatp v, const gs_cie_render * pcrd)
418 {
419 const encode_data_t *data = pcrd->client_data;
420
421 return encode_from_data(v, &data->lmn[gx_cie_cache_size],
422 &pcrd->DomainLMN.ranges[1]);
423 }
424 private float
425 encode_lmn_2_from_data(floatp v, const gs_cie_render * pcrd)
426 {
427 const encode_data_t *data = pcrd->client_data;
428
429 return encode_from_data(v, &data->lmn[gx_cie_cache_size * 2],
430 &pcrd->DomainLMN.ranges[2]);
431 }
432 private float
433 encode_abc_0_from_data(floatp v, const gs_cie_render * pcrd)
434 {
435 const encode_data_t *data = pcrd->client_data;
436
437 return encode_from_data(v, &data->abc[0],
438 &pcrd->DomainABC.ranges[0]);
439 }
440 private float
441 encode_abc_1_from_data(floatp v, const gs_cie_render * pcrd)
442 {
443 const encode_data_t *data = pcrd->client_data;
444
445 return encode_from_data(v, &data->abc[gx_cie_cache_size],
446 &pcrd->DomainABC.ranges[1]);
447 }
448 private float
449 encode_abc_2_from_data(floatp v, const gs_cie_render * pcrd)
450 {
451 const encode_data_t *data = pcrd->client_data;
452
453 return encode_from_data(v, &data->abc[gx_cie_cache_size * 2],
454 &pcrd->DomainABC.ranges[2]);
455 }
456 private frac
457 render_table_t_0_from_data(byte v, const gs_cie_render * pcrd)
458 {
459 const encode_data_t *data = pcrd->client_data;
460
461 return float2frac(encode_from_data(v / 255.0,
462 &data->t[0],
463 &Range3_default.ranges[0]));
464 }
465 private frac
466 render_table_t_1_from_data(byte v, const gs_cie_render * pcrd)
467 {
468 const encode_data_t *data = pcrd->client_data;
469
470 return float2frac(encode_from_data(v / 255.0,
471 &data->t[gx_cie_cache_size],
472 &Range3_default.ranges[0]));
473 }
474 private frac
475 render_table_t_2_from_data(byte v, const gs_cie_render * pcrd)
476 {
477 const encode_data_t *data = pcrd->client_data;
478
479 return float2frac(encode_from_data(v / 255.0,
480 &data->t[gx_cie_cache_size * 2],
481 &Range3_default.ranges[0]));
482 }
483 private frac
484 render_table_t_3_from_data(byte v, const gs_cie_render * pcrd)
485 {
486 const encode_data_t *data = pcrd->client_data;
487
488 return float2frac(encode_from_data(v / 255.0,
489 &data->t[gx_cie_cache_size * 3],
490 &Range3_default.ranges[0]));
491 }
492 private const gs_cie_render_proc3 EncodeLMN_from_data = {
493 {encode_lmn_0_from_data, encode_lmn_1_from_data, encode_lmn_2_from_data}
494 };
495 private const gs_cie_render_proc3 EncodeABC_from_data = {
496 {encode_abc_0_from_data, encode_abc_1_from_data, encode_abc_2_from_data}
497 };
498 private const gs_cie_render_table_procs RenderTableT_from_data = {
499 {render_table_t_0_from_data, render_table_t_1_from_data,
500 render_table_t_2_from_data, render_table_t_3_from_data
501 }
502 };
503
504 /* Read a CRD directly from a parameter list. */
505 int
506 param_get_cie_render1(gs_cie_render * pcrd, gs_param_list * plist,
507 gx_device * dev)
508 {
509 encode_data_t data;
510 gs_param_int_array rt_size;
511 int crd_type;
512 int code, code_lmn, code_abc, code_rt, code_t;
513 gs_param_string pname, pdata;
514
515 if ((code = param_read_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
516 crd_type != CRD_TYPE ||
517 (code = read_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint,
518 NULL)) < 0 ||
519 (code = read_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint,
520 &BlackPoint_default)) < 0 ||
521 (code = read_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
522 (code = read_range3(plist, "RangePQR", &pcrd->RangePQR)) < 0 ||
523 /* TransformPQR is handled specially below. */
524 (code = read_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
525 (code_lmn = code =
526 read_proc3(plist, "EncodeLMNValues", data.lmn)) < 0 ||
527 (code = read_range3(plist, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
528 (code = read_matrix3(plist, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
529 (code_abc = code =
530 read_proc3(plist, "EncodeABCValues", data.abc)) < 0 ||
531 (code = read_range3(plist, "RangeABC", &pcrd->RangeABC)) < 0
532 )
533 return code;
534 /* Handle the sampled functions. */
535 switch (code = param_read_string(plist, "TransformPQRName", &pname)) {
536 default: /* error */
537 return code;
538 case 1: /* missing */
539 pcrd->TransformPQR = TransformPQR_default;
540 break;
541 case 0: /* specified */
542 /* The procedure name must be null-terminated: */
543 /* see param_put_cie_render1 above. */
544 if (pname.size < 1 || pname.data[pname.size - 1] != 0)
545 return_error(gs_error_rangecheck);
546 pcrd->TransformPQR.proc = TransformPQR_lookup_proc_name;
547 pcrd->TransformPQR.proc_name = (char *)pname.data;
548 switch (code = param_read_string(plist, "TransformPQRData", &pdata)) {
549 default: /* error */
550 return code;
551 case 1: /* missing */
552 pcrd->TransformPQR.proc_data.data = 0;
553 pcrd->TransformPQR.proc_data.size = 0;
554 break;
555 case 0:
556 pcrd->TransformPQR.proc_data.data = pdata.data;
557 pcrd->TransformPQR.proc_data.size = pdata.size;
558 }
559 pcrd->TransformPQR.driver_name = gs_devicename(dev);
560 break;
561 }
562 pcrd->client_data = &data;
563 if (code_lmn > 0)
564 pcrd->EncodeLMN = Encode_default;
565 else
566 pcrd->EncodeLMN = EncodeLMN_from_data;
567 if (code_abc > 0)
568 pcrd->EncodeABC = Encode_default;
569 else
570 pcrd->EncodeABC = EncodeABC_from_data;
571 code_rt = code = param_read_int_array(plist, "RenderTableSize", &rt_size);
572 if (code == 1) {
573 if (pcrd->RenderTable.lookup.table) {
574 gs_free_object(pcrd->rc.memory,
575 (void *)pcrd->RenderTable.lookup.table, /* break const */
576 "param_get_cie_render1(RenderTable)");
577 pcrd->RenderTable.lookup.table = 0;
578 }
579 pcrd->RenderTable.T = RenderTableT_default;
580 code_t = 1;
581 } else if (code < 0)
582 return code;
583 else if (rt_size.size != 4)
584 return_error(gs_error_rangecheck);
585 else {
586 gs_param_string_array rt_values;
587 gs_const_string *table;
588 int n, m, j;
589
590 code = param_read_string_array(plist, "RenderTableTable", &rt_values);
591 if (code < 0)
592 return code;
593 else if (code > 0 ||
594 rt_values.size != rt_size.data[3] *
595 rt_size.data[1] * rt_size.data[2])
596 return_error(gs_error_rangecheck);
597 pcrd->RenderTable.lookup.n = n = rt_size.size - 1;
598 pcrd->RenderTable.lookup.m = m = rt_size.data[n];
599 if (n > 4 || m > 4)
600 return_error(gs_error_rangecheck);
601 memcpy(pcrd->RenderTable.lookup.dims, rt_size.data, n * sizeof(int));
602 table = (gs_const_string *)gs_malloc(pcrd->RenderTable.lookup.dims[0],
603 sizeof(gs_const_string *),
604 "param_get_cie_render1");
605 for (j = 0; j < pcrd->RenderTable.lookup.dims[0]; ++j) {
606 table[j].data = rt_values.data[j].data;
607 table[j].size = rt_values.data[j].size;
608 }
609 pcrd->RenderTable.lookup.table = table;
610 pcrd->RenderTable.T = RenderTableT_from_data;
611 code_t = code = read_floats(plist, "RenderTableTValues", data.t,
612 gx_cie_cache_size * m);
613 if (code > 0)
614 pcrd->RenderTable.T = RenderTableT_default;
615 else if (code == 0)
616 pcrd->RenderTable.T = RenderTableT_from_data;
617 }
618 if ((code = gs_cie_render_init(pcrd)) >= 0 &&
619 (code = gs_cie_render_sample(pcrd)) >= 0
620 )
621 code = gs_cie_render_complete(pcrd);
622 /* Clean up before exiting. */
623 pcrd->client_data = 0;
624 if (code_lmn == 0)
625 pcrd->EncodeLMN = EncodeLMN_from_cache;
626 if (code_abc == 0)
627 pcrd->EncodeABC = EncodeABC_from_cache;
628 if (code_t == 0)
629 pcrd->RenderTable.T = RenderTableT_from_cache;
630 return code;
631 }