1 /**************************************************************************/
2 /*                                                                        */
3 /* Copyright (c) 2001, 2010 NoMachine, http://www.nomachine.com/.         */
4 /*                                                                        */
5 /* NXCOMP, NX protocol compression and NX extensions to this software     */
6 /* are copyright of NoMachine. Redistribution and use of the present      */
7 /* software is allowed according to terms specified in the file LICENSE   */
8 /* which comes in the source distribution.                                */
9 /*                                                                        */
10 /* Check http://www.nomachine.com/licensing.html for applicability.       */
11 /*                                                                        */
12 /* NX and NoMachine are trademarks of Medialogic S.p.A.                   */
13 /*                                                                        */
14 /* All rights reserved.                                                   */
15 /*                                                                        */
16 /**************************************************************************/
17 
18 //
19 // Include the template for
20 // this message class.
21 //
22 
23 #include "RenderCompositeGlyphs.h"
24 
25 //
26 // Set the verbosity level.
27 //
28 
29 #define PANIC
30 #define WARNING
31 #undef  TEST
32 #undef  DEBUG
33 
34 #include MESSAGE_TAGS
35 
36 //
37 // Message handling methods.
38 //
39 
40 MESSAGE_BEGIN_ENCODE_SIZE
41 {
42   ClientCache *clientCache = (ClientCache *) channelCache;
43 
44   #ifdef DEBUG
45   *logofs << name() << ": Encoding value "
46           << ((size - MESSAGE_OFFSET) >> 2) << ".\n"
47           << logofs_flush;
48   #endif
49 
50   encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16,
51                      clientCache -> renderLengthCache, 5);
52 
53   #ifdef TEST
54   *logofs << name() << ": Encoded size with value "
55           << size << ".\n" << logofs_flush;
56   #endif
57 }
58 MESSAGE_END_ENCODE_SIZE
59 
60 MESSAGE_BEGIN_DECODE_SIZE
61 {
62   ClientCache *clientCache = (ClientCache *) channelCache;
63 
64   decodeBuffer.decodeCachedValue(size, 16,
65                      clientCache -> renderLengthCache, 5);
66 
67   #ifdef DEBUG
68   *logofs << name() << ": Decoded value " << size
69           << ".\n" << logofs_flush;
70   #endif
71 
72   size = MESSAGE_OFFSET + (size << 2);
73 
74   buffer = writeBuffer -> addMessage(size);
75 
76   #ifdef TEST
77   *logofs << name() << ": Decoded size with value "
78           << size << ".\n" << logofs_flush;
79   #endif
80 }
81 MESSAGE_END_DECODE_SIZE
82 
83 MESSAGE_BEGIN_ENCODE_MESSAGE
84 {
85   ClientCache *clientCache = (ClientCache *) channelCache;
86 
87   encodeBuffer.encodeCachedValue(*(buffer + 4), 8,
88                      clientCache -> renderOpCache);
89 
90   encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian),
91                      clientCache -> renderSrcPictureCache);
92 
93   encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian),
94                      clientCache -> renderDstPictureCache);
95 
96   encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32,
97                      clientCache -> renderFormatCache);
98 
99   encodeBuffer.encodeCachedValue(GetULONG(buffer + 20, bigEndian), 29,
100                      clientCache -> renderGlyphSetCache);
101 
102   unsigned int src_x = GetUINT(buffer + 24, bigEndian);
103   unsigned int src_y = GetUINT(buffer + 26, bigEndian);
104 
105   if (control -> isProtoStep8() == 1)
106   {
107     encodeBuffer.encodeDiffCachedValue(src_x,
108                        clientCache -> renderGlyphX, 16,
109                            clientCache -> renderGlyphXCache, 11);
110 
111     encodeBuffer.encodeDiffCachedValue(src_y,
112                        clientCache -> renderGlyphY, 16,
113                            clientCache -> renderGlyphYCache, 11);
114   }
115   else
116   {
117     encodeBuffer.encodeDiffCachedValue(src_x,
118                        clientCache -> renderLastX, 16,
119                            clientCache -> renderXCache, 11);
120 
121     encodeBuffer.encodeDiffCachedValue(src_y,
122                        clientCache -> renderLastY, 16,
123                            clientCache -> renderYCache, 11);
124   }
125 
126   #ifdef TEST
127   *logofs << name() << ": Encoded source X "
128           << GetUINT(buffer + 24, bigEndian) << " source Y "
129           << GetUINT(buffer + 26, bigEndian) << ".\n"
130           << logofs_flush;
131   #endif
132 
133   //
134   // Bytes from 28 to 36 contain in the order:
135   //
136   // 1 byte for the length of the first string.
137   // 3 bytes of padding.
138   // 2 bytes for the X offset.
139   // 2 bytes for the Y offset.
140   //
141   // Encode these bytes differentially to match
142   // all the strings that have equal glyphs.
143   //
144   // Only manage the first string of glyphs. The
145   // others strings should match, if they contain
146   // the same glyphs, since the offset are rela-
147   // tive to the first offset coordinates.
148   //
149 
150   if (control -> isProtoStep8() == 1 &&
151           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
152   {
153     unsigned int numGlyphs = *(buffer + 28);
154 
155     encodeBuffer.encodeCachedValue(numGlyphs, 8,
156                        clientCache -> renderNumGlyphsCache);
157 
158     unsigned int offset_x = GetUINT(buffer + 32, bigEndian);
159     unsigned int offset_y = GetUINT(buffer + 34, bigEndian);
160 
161     if (offset_x == src_x && offset_y == src_y)
162     {
163       encodeBuffer.encodeBoolValue(0);
164 
165       #ifdef TEST
166       *logofs << name() << ": Matched offset X "
167               << GetUINT(buffer + 32, bigEndian) << " offset Y "
168               << GetUINT(buffer + 34, bigEndian) << ".\n"
169               << logofs_flush;
170       #endif
171     }
172     else
173     {
174       encodeBuffer.encodeBoolValue(1);
175 
176       encodeBuffer.encodeDiffCachedValue(offset_x,
177                          clientCache -> renderGlyphX, 16,
178                              clientCache -> renderGlyphXCache, 11);
179 
180       encodeBuffer.encodeDiffCachedValue(offset_y,
181                          clientCache -> renderGlyphY, 16,
182                              clientCache -> renderGlyphYCache, 11);
183 
184       #ifdef TEST
185       *logofs << name() << ": Missed offset X "
186               << GetUINT(buffer + 32, bigEndian) << " offset Y "
187               << GetUINT(buffer + 34, bigEndian) << ".\n"
188               << logofs_flush;
189       #endif
190     }
191   }
192 
193   #ifdef TEST
194   *logofs << name() << ": Encoded message. Type is "
195           << (unsigned int) *(buffer + 1) << " size is "
196           << size << ".\n" << logofs_flush;
197   #endif
198 }
199 MESSAGE_END_ENCODE_MESSAGE
200 
201 MESSAGE_BEGIN_DECODE_MESSAGE
202 {
203   ClientCache *clientCache = (ClientCache *) channelCache;
204 
205   unsigned int value;
206 
207   *(buffer + 1) = type;
208 
209   decodeBuffer.decodeCachedValue(*(buffer + 4), 8,
210                      clientCache -> renderOpCache);
211 
212   decodeBuffer.decodeXidValue(value,
213                      clientCache -> renderSrcPictureCache);
214 
215   PutULONG(value, buffer + 8, bigEndian);
216 
217   decodeBuffer.decodeXidValue(value,
218                      clientCache -> renderDstPictureCache);
219 
220   PutULONG(value, buffer + 12, bigEndian);
221 
222   decodeBuffer.decodeCachedValue(value, 32,
223                      clientCache -> renderFormatCache);
224 
225   PutULONG(value, buffer + 16, bigEndian);
226 
227   decodeBuffer.decodeCachedValue(value, 29,
228                      clientCache -> renderGlyphSetCache);
229 
230   PutULONG(value, buffer + 20, bigEndian);
231 
232   unsigned int src_x;
233   unsigned int src_y;
234 
235   if (control -> isProtoStep8() == 1)
236   {
237     decodeBuffer.decodeDiffCachedValue(src_x,
238                        clientCache -> renderGlyphX, 16,
239                            clientCache -> renderGlyphXCache, 11);
240 
241     decodeBuffer.decodeDiffCachedValue(src_y,
242                        clientCache -> renderGlyphY, 16,
243                            clientCache -> renderGlyphYCache, 11);
244   }
245   else
246   {
247     decodeBuffer.decodeDiffCachedValue(src_x,
248                        clientCache -> renderLastX, 16,
249                            clientCache -> renderXCache, 11);
250 
251     decodeBuffer.decodeDiffCachedValue(src_y,
252                        clientCache -> renderLastY, 16,
253                            clientCache -> renderYCache, 11);
254   }
255 
256   PutUINT(src_x, buffer + 24, bigEndian);
257   PutUINT(src_y, buffer + 26, bigEndian);
258 
259   if (control -> isProtoStep8() == 1 &&
260           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
261   {
262     decodeBuffer.decodeCachedValue(value, 8,
263                        clientCache -> renderNumGlyphsCache);
264 
265     *(buffer + 28) = value;
266 
267     decodeBuffer.decodeBoolValue(value);
268 
269     if (value == 0)
270     {
271       PutUINT(src_x, buffer + 32, bigEndian);
272       PutUINT(src_y, buffer + 34, bigEndian);
273     }
274     else
275     {
276       decodeBuffer.decodeDiffCachedValue(src_x,
277                          clientCache -> renderGlyphX, 16,
278                              clientCache -> renderGlyphXCache, 11);
279 
280       PutUINT(src_x, buffer + 32, bigEndian);
281 
282       decodeBuffer.decodeDiffCachedValue(src_y,
283                          clientCache -> renderGlyphY, 16,
284                              clientCache -> renderGlyphYCache, 11);
285 
286       PutUINT(src_y, buffer + 34, bigEndian);
287     }
288   }
289 
290   #ifdef TEST
291   *logofs << name() << ": Decoded message. Type is "
292           << (unsigned int) type << " size is " << size
293           << ".\n" << logofs_flush;
294   #endif
295 }
296 MESSAGE_END_DECODE_MESSAGE
297 
298 MESSAGE_BEGIN_ENCODE_DATA
299 {
300   if (control -> isProtoStep8() == 1 &&
301           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
302   {
303     encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET_IF_PROTO_STEP_8,
304                        size, bigEndian, channelCache);
305   }
306   else if (size > MESSAGE_OFFSET)
307   {
308     encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET,
309                        size, bigEndian, channelCache);
310   }
311 
312   #ifdef TEST
313   *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET
314           << " bytes of text data.\n" << logofs_flush;
315   #endif
316 }
317 MESSAGE_END_ENCODE_DATA
318 
319 MESSAGE_BEGIN_DECODE_DATA
320 {
321   if (control -> isProtoStep8() == 1 &&
322           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
323   {
324     decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET_IF_PROTO_STEP_8,
325                        size, bigEndian, channelCache);
326   }
327   else if (size > MESSAGE_OFFSET)
328   {
329     decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET,
330                        size, bigEndian, channelCache);
331   }
332 
333   #ifdef TEST
334   *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET
335           << " bytes of data.\n" << logofs_flush;
336   #endif
337 }
338 MESSAGE_END_DECODE_DATA
339 
340 MESSAGE_BEGIN_PARSE_IDENTITY
341 {
342   RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message;
343 
344   renderExtension -> data.composite_glyphs.type = *(buffer + 1);
345   renderExtension -> data.composite_glyphs.op   = *(buffer + 4);
346 
347   renderExtension -> data.composite_glyphs.src_id = GetULONG(buffer + 8,  bigEndian);
348   renderExtension -> data.composite_glyphs.dst_id = GetULONG(buffer + 12, bigEndian);
349 
350   renderExtension -> data.composite_glyphs.format = GetULONG(buffer + 16, bigEndian);
351   renderExtension -> data.composite_glyphs.set_id = GetULONG(buffer + 20, bigEndian);
352 
353   renderExtension -> data.composite_glyphs.src_x = GetUINT(buffer + 24, bigEndian);
354   renderExtension -> data.composite_glyphs.src_y = GetUINT(buffer + 26, bigEndian);
355 
356   if (control -> isProtoStep8() == 1 &&
357           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
358   {
359     renderExtension -> data.composite_glyphs.num_elm = *(buffer + 28);
360 
361     renderExtension -> data.composite_glyphs.offset_x = GetUINT(buffer + 32, bigEndian);
362     renderExtension -> data.composite_glyphs.offset_y = GetUINT(buffer + 34, bigEndian);
363   }
364 
365   #ifdef TEST
366   *logofs << name() << ": Parsed identity. Type is "
367           << (unsigned int) renderExtension -> data.composite_glyphs.type
368           << " size is " << renderExtension -> size_ << " identity size "
369           << renderExtension -> i_size_ << ".\n" << logofs_flush;
370   #endif
371 }
372 MESSAGE_END_PARSE_IDENTITY
373 
374 MESSAGE_BEGIN_UNPARSE_IDENTITY
375 {
376   RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message;
377 
378   *(buffer + 1) = renderExtension -> data.composite_glyphs.type;
379   *(buffer + 4) = renderExtension -> data.composite_glyphs.op;
380 
381   PutULONG(renderExtension -> data.composite_glyphs.src_id, buffer + 8,  bigEndian);
382   PutULONG(renderExtension -> data.composite_glyphs.dst_id, buffer + 12, bigEndian);
383 
384   PutULONG(renderExtension -> data.composite_glyphs.format, buffer + 16, bigEndian);
385   PutULONG(renderExtension -> data.composite_glyphs.set_id, buffer + 20, bigEndian);
386 
387   PutUINT(renderExtension -> data.composite_glyphs.src_x, buffer + 24, bigEndian);
388   PutUINT(renderExtension -> data.composite_glyphs.src_y, buffer + 26, bigEndian);
389 
390   if (control -> isProtoStep8() == 1 &&
391           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
392   {
393     *(buffer + 28) = renderExtension -> data.composite_glyphs.num_elm;
394 
395     PutUINT(renderExtension -> data.composite_glyphs.offset_x, buffer + 32, bigEndian);
396     PutUINT(renderExtension -> data.composite_glyphs.offset_y, buffer + 34, bigEndian);
397   }
398 
399   #ifdef TEST
400   *logofs << name() << ": Unparsed identity. Type is "
401           << (unsigned int) renderExtension -> data.composite_glyphs.type
402           << " size is " << renderExtension -> size_  << " identity size "
403           << renderExtension -> i_size_ <<  ".\n" << logofs_flush;
404   #endif
405 }
406 MESSAGE_END_UNPARSE_IDENTITY
407 
408 MESSAGE_BEGIN_IDENTITY_CHECKSUM
409 {
410   //
411   // Include minor opcode, size and
412   // the composite operator in the
413   // identity.
414   //
415 
416   md5_append(md5_state, buffer + 1, 4);
417 
418   //
419   // Include the format.
420   //
421 
422   md5_append(md5_state, buffer + 16, 4);
423 
424   //
425   // Also include the length of the
426   // first string.
427   //
428 
429   if (control -> isProtoStep8() == 1 &&
430           size >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
431   {
432     md5_append(md5_state, buffer + 28, 1);
433   }
434 }
435 MESSAGE_END_IDENTITY_CHECKSUM
436 
437 MESSAGE_BEGIN_ENCODE_UPDATE
438 {
439   RenderExtensionMessage *renderExtension       = (RenderExtensionMessage *) message;
440   RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage;
441 
442   ClientCache *clientCache = (ClientCache *) channelCache;
443 
444   encodeBuffer.encodeXidValue(renderExtension -> data.composite_glyphs.src_id,
445                      clientCache -> renderSrcPictureCache);
446 
447   cachedRenderExtension -> data.composite_glyphs.src_id =
448               renderExtension -> data.composite_glyphs.src_id;
449 
450   encodeBuffer.encodeXidValue(renderExtension -> data.composite_glyphs.dst_id,
451                      clientCache -> renderDstPictureCache);
452 
453   cachedRenderExtension -> data.composite_glyphs.dst_id =
454               renderExtension -> data.composite_glyphs.dst_id;
455 
456   encodeBuffer.encodeCachedValue(renderExtension -> data.composite_glyphs.set_id, 29,
457                      clientCache -> renderGlyphSetCache);
458 
459   cachedRenderExtension -> data.composite_glyphs.set_id =
460               renderExtension -> data.composite_glyphs.set_id;
461 
462   //
463   // Src X and Y.
464   //
465   // The source X and Y coordinates are
466   // encoded as differerences in respect
467   // to the cached message.
468   //
469 
470   unsigned int value;
471   unsigned int previous;
472 
473   if (control -> isProtoStep8() == 1)
474   {
475     value    = renderExtension -> data.composite_glyphs.src_x;
476     previous = cachedRenderExtension -> data.composite_glyphs.src_x;
477 
478     encodeBuffer.encodeDiffCachedValue(value, previous, 16,
479                        clientCache -> renderGlyphXCache, 11);
480 
481     cachedRenderExtension -> data.composite_glyphs.src_x = value;
482 
483     value    = renderExtension -> data.composite_glyphs.src_y;
484     previous = cachedRenderExtension -> data.composite_glyphs.src_y;
485 
486     encodeBuffer.encodeDiffCachedValue(value, previous, 16,
487                        clientCache -> renderGlyphYCache, 11);
488 
489     cachedRenderExtension -> data.composite_glyphs.src_y = value;
490   }
491   else
492   {
493     value    = renderExtension -> data.composite_glyphs.src_x;
494     previous = cachedRenderExtension -> data.composite_glyphs.src_x;
495 
496     encodeBuffer.encodeDiffCachedValue(value, previous, 16,
497                        clientCache -> renderXCache, 11);
498 
499     cachedRenderExtension -> data.composite_glyphs.src_x = value;
500 
501     value    = renderExtension -> data.composite_glyphs.src_y;
502     previous = cachedRenderExtension -> data.composite_glyphs.src_y;
503 
504     encodeBuffer.encodeDiffCachedValue(value, previous, 16,
505                        clientCache -> renderYCache, 11);
506 
507     cachedRenderExtension -> data.composite_glyphs.src_y = value;
508   }
509 
510   #ifdef TEST
511   *logofs << name() << ": Encoded source X "
512           << renderExtension -> data.composite_glyphs.src_x << " source Y "
513           << renderExtension -> data.composite_glyphs.src_y << ".\n"
514           << logofs_flush;
515   #endif
516 
517   if (control -> isProtoStep8() == 1 &&
518           renderExtension -> size_ >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
519   {
520     //
521     // Offset X and Y.
522     //
523 
524     if (renderExtension -> data.composite_glyphs.offset_x ==
525             renderExtension -> data.composite_glyphs.src_x &&
526                 renderExtension -> data.composite_glyphs.offset_y ==
527                     renderExtension -> data.composite_glyphs.src_y)
528     {
529       encodeBuffer.encodeBoolValue(0);
530 
531       cachedRenderExtension -> data.composite_glyphs.offset_x =
532             renderExtension -> data.composite_glyphs.offset_x;
533 
534       cachedRenderExtension -> data.composite_glyphs.offset_y =
535             renderExtension -> data.composite_glyphs.offset_y;
536 
537       #ifdef TEST
538       *logofs << name() << ": Matched offset X "
539               << renderExtension -> data.composite_glyphs.offset_x << " offset Y "
540               << renderExtension -> data.composite_glyphs.offset_y << ".\n"
541               << logofs_flush;
542       #endif
543     }
544     else
545     {
546       encodeBuffer.encodeBoolValue(1);
547 
548       value    = renderExtension -> data.composite_glyphs.offset_x;
549       previous = cachedRenderExtension -> data.composite_glyphs.offset_x;
550 
551       encodeBuffer.encodeDiffCachedValue(value, previous, 16,
552                          clientCache -> renderGlyphXCache, 11);
553 
554       cachedRenderExtension -> data.composite_glyphs.offset_x = value;
555 
556       value    = renderExtension -> data.composite_glyphs.offset_y;
557       previous = cachedRenderExtension -> data.composite_glyphs.offset_y;
558 
559       encodeBuffer.encodeDiffCachedValue(value, previous, 16,
560                          clientCache -> renderGlyphYCache, 11);
561 
562       cachedRenderExtension -> data.composite_glyphs.offset_y = value;
563 
564       #ifdef TEST
565       *logofs << name() << ": Missed offset X "
566               << renderExtension -> data.composite_glyphs.offset_x << " offset Y "
567               << renderExtension -> data.composite_glyphs.offset_y << ".\n"
568               << logofs_flush;
569       #endif
570     }
571   }
572 
573   #ifdef TEST
574   *logofs << name() << ": Encoded update. Type is "
575           << (unsigned int) renderExtension -> data.composite_glyphs.type
576           << " size is " << renderExtension -> size_ << ".\n"
577           << logofs_flush;
578   #endif
579 }
580 MESSAGE_END_ENCODE_UPDATE
581 
582 MESSAGE_BEGIN_DECODE_UPDATE
583 {
584   RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message;
585 
586   ClientCache *clientCache = (ClientCache *) channelCache;
587 
588   decodeBuffer.decodeXidValue(renderExtension -> data.composite_glyphs.src_id,
589                      clientCache -> renderSrcPictureCache);
590 
591   decodeBuffer.decodeXidValue(renderExtension -> data.composite_glyphs.dst_id,
592                      clientCache -> renderDstPictureCache);
593 
594   decodeBuffer.decodeCachedValue(renderExtension -> data.composite_glyphs.set_id, 29,
595                      clientCache -> renderGlyphSetCache);
596 
597   //
598   // Src X and Y.
599   //
600 
601   unsigned int value;
602   unsigned int previous;
603 
604   if (control -> isProtoStep8() == 1)
605   {
606     previous = renderExtension -> data.composite_glyphs.src_x;
607 
608     decodeBuffer.decodeDiffCachedValue(value, previous, 16,
609                        clientCache -> renderGlyphXCache, 11);
610 
611     renderExtension -> data.composite_glyphs.src_x = value;
612 
613     previous = renderExtension -> data.composite_glyphs.src_y;
614 
615     decodeBuffer.decodeDiffCachedValue(value, previous, 16,
616                        clientCache -> renderGlyphYCache, 11);
617 
618     renderExtension -> data.composite_glyphs.src_y = value;
619   }
620   else
621   {
622     previous = renderExtension -> data.composite_glyphs.src_x;
623 
624     decodeBuffer.decodeDiffCachedValue(value, previous, 16,
625                        clientCache -> renderXCache, 11);
626 
627     renderExtension -> data.composite_glyphs.src_x = value;
628 
629     previous = renderExtension -> data.composite_glyphs.src_y;
630 
631     decodeBuffer.decodeDiffCachedValue(value, previous, 16,
632                        clientCache -> renderYCache, 11);
633 
634     renderExtension -> data.composite_glyphs.src_y = value;
635   }
636 
637   if (control -> isProtoStep8() == 1 &&
638           renderExtension -> size_ >= MESSAGE_OFFSET_IF_PROTO_STEP_8)
639   {
640     //
641     // Offset X and Y.
642     //
643 
644     decodeBuffer.decodeBoolValue(value);
645 
646     if (value == 0)
647     {
648       renderExtension -> data.composite_glyphs.offset_x =
649             renderExtension -> data.composite_glyphs.src_x;
650 
651       renderExtension -> data.composite_glyphs.offset_y =
652             renderExtension -> data.composite_glyphs.src_y;
653     }
654     else
655     {
656       previous = renderExtension -> data.composite_glyphs.offset_x;
657 
658       decodeBuffer.decodeDiffCachedValue(value, previous, 16,
659                          clientCache -> renderGlyphXCache, 11);
660 
661       renderExtension -> data.composite_glyphs.offset_x = value;
662 
663       previous = renderExtension -> data.composite_glyphs.offset_y;
664 
665       decodeBuffer.decodeDiffCachedValue(value, previous, 16,
666                          clientCache -> renderGlyphYCache, 11);
667 
668       renderExtension -> data.composite_glyphs.offset_y = value;
669     }
670   }
671 
672   #ifdef TEST
673   *logofs << name() << ": Decoded update. Type is "
674           << (unsigned int) renderExtension -> data.composite_glyphs.type
675           << " size is " << renderExtension -> size_ << ".\n"
676           << logofs_flush;
677   #endif
678 }
679 MESSAGE_END_DECODE_UPDATE
680