1/****************************************************************************
2 *
3 * ftbitmap.c
4 *
5 * FreeType utility functions for bitmaps (body).
6 *
7 * Copyright (C) 2004-2019 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19#include <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21
22#include FT_BITMAP_H
23#include FT_IMAGE_H
24#include FT_INTERNAL_OBJECTS_H
25
26
27 /**************************************************************************
28 *
29 * The macro FT_COMPONENT is used in trace mode. It is an implicit
30 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
31 * messages during execution.
32 */
33#undef FT_COMPONENT
34#define FT_COMPONENT bitmap
35
36
37 static
38 const FT_Bitmap null_bitmap = { 0, 0, 0, NULL, 0, 0, 0, NULL };
39
40
41 /* documentation is in ftbitmap.h */
42
43 FT_EXPORT_DEF( void )
44 FT_Bitmap_Init( FT_Bitmap *abitmap )
45 {
46 if ( abitmap )
47 *abitmap = null_bitmap;
48 }
49
50
51 /* deprecated function name; retained for ABI compatibility */
52
53 FT_EXPORT_DEF( void )
54 FT_Bitmap_New( FT_Bitmap *abitmap )
55 {
56 if ( abitmap )
57 *abitmap = null_bitmap;
58 }
59
60
61 /* documentation is in ftbitmap.h */
62
63 FT_EXPORT_DEF( FT_Error )
64 FT_Bitmap_Copy( FT_Library library,
65 const FT_Bitmap *source,
66 FT_Bitmap *target)
67 {
68 FT_Memory memory;
69 FT_Error error = FT_Err_Ok;
70
71 FT_Int pitch;
72 FT_ULong size;
73
74 FT_Int source_pitch_sign, target_pitch_sign;
75
76
77 if ( !library )
78 return FT_THROW( Invalid_Library_Handle );
79
80 if ( !source || !target )
81 return FT_THROW( Invalid_Argument );
82
83 if ( source == target )
84 return FT_Err_Ok;
85
86 source_pitch_sign = source->pitch < 0 ? -1 : 1;
87 target_pitch_sign = target->pitch < 0 ? -1 : 1;
88
89 if ( !source->buffer )
90 {
91 *target = *source;
92 if ( source_pitch_sign != target_pitch_sign )
93 target->pitch = -target->pitch;
94
95 return FT_Err_Ok;
96 }
97
98 memory = library->memory;
99 pitch = source->pitch;
100
101 if ( pitch < 0 )
102 pitch = -pitch;
103 size = (FT_ULong)pitch * source->rows;
104
105 if ( target->buffer )
106 {
107 FT_Int target_pitch = target->pitch;
108 FT_ULong target_size;
109
110
111 if ( target_pitch < 0 )
112 target_pitch = -target_pitch;
113 target_size = (FT_ULong)target_pitch * target->rows;
114
115 if ( target_size != size )
116 (void)FT_QREALLOC( target->buffer, target_size, size );
117 }
118 else
119 (void)FT_QALLOC( target->buffer, size );
120
121 if ( !error )
122 {
123 unsigned char *p;
124
125
126 p = target->buffer;
127 *target = *source;
128 target->buffer = p;
129
130 if ( source_pitch_sign == target_pitch_sign )
131 FT_MEM_COPY( target->buffer, source->buffer, size );
132 else
133 {
134 /* take care of bitmap flow */
135 FT_UInt i;
136 FT_Byte* s = source->buffer;
137 FT_Byte* t = target->buffer;
138
139
140 t += (FT_ULong)pitch * ( target->rows - 1 );
141
142 for ( i = target->rows; i > 0; i-- )
143 {
144 FT_ARRAY_COPY( t, s, pitch );
145
146 s += pitch;
147 t -= pitch;
148 }
149 }
150 }
151
152 return error;
153 }
154
155
156 /* Enlarge `bitmap' horizontally and vertically by `xpixels' */
157 /* and `ypixels', respectively. */
158
159 static FT_Error
160 ft_bitmap_assure_buffer( FT_Memory memory,
161 FT_Bitmap* bitmap,
162 FT_UInt xpixels,
163 FT_UInt ypixels )
164 {
165 FT_Error error;
166 unsigned int pitch;
167 unsigned int new_pitch;
168 FT_UInt bpp;
169 FT_UInt width, height;
170 unsigned char* buffer = NULL;
171
172
173 width = bitmap->width;
174 height = bitmap->rows;
175 pitch = (unsigned int)FT_ABS( bitmap->pitch );
176
177 switch ( bitmap->pixel_mode )
178 {
179 case FT_PIXEL_MODE_MONO:
180 bpp = 1;
181 new_pitch = ( width + xpixels + 7 ) >> 3;
182 break;
183 case FT_PIXEL_MODE_GRAY2:
184 bpp = 2;
185 new_pitch = ( width + xpixels + 3 ) >> 2;
186 break;
187 case FT_PIXEL_MODE_GRAY4:
188 bpp = 4;
189 new_pitch = ( width + xpixels + 1 ) >> 1;
190 break;
191 case FT_PIXEL_MODE_GRAY:
192 case FT_PIXEL_MODE_LCD:
193 case FT_PIXEL_MODE_LCD_V:
194 bpp = 8;
195 new_pitch = width + xpixels;
196 break;
197 default:
198 return FT_THROW( Invalid_Glyph_Format );
199 }
200
201 /* if no need to allocate memory */
202 if ( ypixels == 0 && new_pitch <= pitch )
203 {
204 /* zero the padding */
205 FT_UInt bit_width = pitch * 8;
206 FT_UInt bit_last = ( width + xpixels ) * bpp;
207
208
209 if ( bit_last < bit_width )
210 {
211 FT_Byte* line = bitmap->buffer + ( bit_last >> 3 );
212 FT_Byte* end = bitmap->buffer + pitch;
213 FT_UInt shift = bit_last & 7;
214 FT_UInt mask = 0xFF00U >> shift;
215 FT_UInt count = height;
216
217
218 for ( ; count > 0; count--, line += pitch, end += pitch )
219 {
220 FT_Byte* write = line;
221
222
223 if ( shift > 0 )
224 {
225 write[0] = (FT_Byte)( write[0] & mask );
226 write++;
227 }
228 if ( write < end )
229 FT_MEM_ZERO( write, end - write );
230 }
231 }
232
233 return FT_Err_Ok;
234 }
235
236 /* otherwise allocate new buffer */
237 if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) )
238 return error;
239
240 /* new rows get added at the top of the bitmap, */
241 /* thus take care of the flow direction */
242 if ( bitmap->pitch > 0 )
243 {
244 FT_UInt len = ( width * bpp + 7 ) >> 3;
245
246 unsigned char* in = bitmap->buffer;
247 unsigned char* out = buffer;
248
249 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows;
250 unsigned int delta = new_pitch - len;
251
252
253 FT_MEM_ZERO( out, new_pitch * ypixels );
254 out += new_pitch * ypixels;
255
256 while ( in < limit )
257 {
258 FT_MEM_COPY( out, in, len );
259 in += pitch;
260 out += len;
261
262 /* we use FT_QALLOC_MULT, which doesn't zero out the buffer; */
263 /* consequently, we have to manually zero out the remaining bytes */
264 FT_MEM_ZERO( out, delta );
265 out += delta;
266 }
267 }
268 else
269 {
270 FT_UInt len = ( width * bpp + 7 ) >> 3;
271
272 unsigned char* in = bitmap->buffer;
273 unsigned char* out = buffer;
274
275 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows;
276 unsigned int delta = new_pitch - len;
277
278
279 while ( in < limit )
280 {
281 FT_MEM_COPY( out, in, len );
282 in += pitch;
283 out += len;
284
285 FT_MEM_ZERO( out, delta );
286 out += delta;
287 }
288
289 FT_MEM_ZERO( out, new_pitch * ypixels );
290 }
291
292 FT_FREE( bitmap->buffer );
293 bitmap->buffer = buffer;
294
295 /* set pitch only, width and height are left untouched */
296 if ( bitmap->pitch < 0 )
297 bitmap->pitch = -(int)new_pitch;
298 else
299 bitmap->pitch = (int)new_pitch;
300
301 return FT_Err_Ok;
302 }
303
304
305 /* documentation is in ftbitmap.h */
306
307 FT_EXPORT_DEF( FT_Error )
308 FT_Bitmap_Embolden( FT_Library library,
309 FT_Bitmap* bitmap,
310 FT_Pos xStrength,
311 FT_Pos yStrength )
312 {
313 FT_Error error;
314 unsigned char* p;
315 FT_Int i, x, pitch;
316 FT_UInt y;
317 FT_Int xstr, ystr;
318
319
320 if ( !library )
321 return FT_THROW( Invalid_Library_Handle );
322
323 if ( !bitmap || !bitmap->buffer )
324 return FT_THROW( Invalid_Argument );
325
326 if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) ||
327 ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) )
328 return FT_THROW( Invalid_Argument );
329
330 xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6;
331 ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6;
332
333 if ( xstr == 0 && ystr == 0 )
334 return FT_Err_Ok;
335 else if ( xstr < 0 || ystr < 0 )
336 return FT_THROW( Invalid_Argument );
337
338 switch ( bitmap->pixel_mode )
339 {
340 case FT_PIXEL_MODE_GRAY2:
341 case FT_PIXEL_MODE_GRAY4:
342 {
343 FT_Bitmap tmp;
344
345
346 /* convert to 8bpp */
347 FT_Bitmap_Init( &tmp );
348 error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 );
349 if ( error )
350 return error;
351
352 FT_Bitmap_Done( library, bitmap );
353 *bitmap = tmp;
354 }
355 break;
356
357 case FT_PIXEL_MODE_MONO:
358 if ( xstr > 8 )
359 xstr = 8;
360 break;
361
362 case FT_PIXEL_MODE_LCD:
363 xstr *= 3;
364 break;
365
366 case FT_PIXEL_MODE_LCD_V:
367 ystr *= 3;
368 break;
369
370 case FT_PIXEL_MODE_BGRA:
371 /* We don't embolden color glyphs. */
372 return FT_Err_Ok;
373 }
374
375 error = ft_bitmap_assure_buffer( library->memory, bitmap,
376 (FT_UInt)xstr, (FT_UInt)ystr );
377 if ( error )
378 return error;
379
380 /* take care of bitmap flow */
381 pitch = bitmap->pitch;
382 if ( pitch > 0 )
383 p = bitmap->buffer + pitch * ystr;
384 else
385 {
386 pitch = -pitch;
387 p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 );
388 }
389
390 /* for each row */
391 for ( y = 0; y < bitmap->rows; y++ )
392 {
393 /*
394 * Horizontally:
395 *
396 * From the last pixel on, make each pixel or'ed with the
397 * `xstr' pixels before it.
398 */
399 for ( x = pitch - 1; x >= 0; x-- )
400 {
401 unsigned char tmp;
402
403
404 tmp = p[x];
405 for ( i = 1; i <= xstr; i++ )
406 {
407 if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO )
408 {
409 p[x] |= tmp >> i;
410
411 /* the maximum value of 8 for `xstr' comes from here */
412 if ( x > 0 )
413 p[x] |= p[x - 1] << ( 8 - i );
414
415#if 0
416 if ( p[x] == 0xFF )
417 break;
418#endif
419 }
420 else
421 {
422 if ( x - i >= 0 )
423 {
424 if ( p[x] + p[x - i] > bitmap->num_grays - 1 )
425 {
426 p[x] = (unsigned char)( bitmap->num_grays - 1 );
427 break;
428 }
429 else
430 {
431 p[x] = (unsigned char)( p[x] + p[x - i] );
432 if ( p[x] == bitmap->num_grays - 1 )
433 break;
434 }
435 }
436 else
437 break;
438 }
439 }
440 }
441
442 /*
443 * Vertically:
444 *
445 * Make the above `ystr' rows or'ed with it.
446 */
447 for ( x = 1; x <= ystr; x++ )
448 {
449 unsigned char* q;
450
451
452 q = p - bitmap->pitch * x;
453 for ( i = 0; i < pitch; i++ )
454 q[i] |= p[i];
455 }
456
457 p += bitmap->pitch;
458 }
459
460 bitmap->width += (FT_UInt)xstr;
461 bitmap->rows += (FT_UInt)ystr;
462
463 return FT_Err_Ok;
464 }
465
466
467 static FT_Byte
468 ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra )
469 {
470 FT_UInt a = bgra[3];
471 FT_UInt l;
472
473
474 /* Short-circuit transparent color to avoid division by zero. */
475 if ( !a )
476 return 0;
477
478 /*
479 * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722
480 * coefficients for RGB channels *on the linear colors*.
481 * A gamma of 2.2 is fair to assume. And then, we need to
482 * undo the premultiplication too.
483 *
484 * https://accessibility.kde.org/hsl-adjusted.php
485 *
486 * We do the computation with integers only, applying a gamma of 2.0.
487 * We guarantee 32-bit arithmetic to avoid overflow but the resulting
488 * luminosity fits into 16 bits.
489 *
490 */
491
492 l = ( 4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] +
493 46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] +
494 13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16;
495
496 /*
497 * Final transparency can be determined as follows.
498 *
499 * - If alpha is zero, we want 0.
500 * - If alpha is zero and luminosity is zero, we want 255.
501 * - If alpha is zero and luminosity is one, we want 0.
502 *
503 * So the formula is a * (1 - l) = a - l * a.
504 *
505 * We still need to undo premultiplication by dividing l by a*a.
506 *
507 */
508
509 return (FT_Byte)( a - l / a );
510 }
511
512
513 /* documentation is in ftbitmap.h */
514
515 FT_EXPORT_DEF( FT_Error )
516 FT_Bitmap_Convert( FT_Library library,
517 const FT_Bitmap *source,
518 FT_Bitmap *target,
519 FT_Int alignment )
520 {
521 FT_Error error = FT_Err_Ok;
522 FT_Memory memory;
523
524 FT_Byte* s;
525 FT_Byte* t;
526
527
528 if ( !library )
529 return FT_THROW( Invalid_Library_Handle );
530
531 if ( !source || !target )
532 return FT_THROW( Invalid_Argument );
533
534 memory = library->memory;
535
536 switch ( source->pixel_mode )
537 {
538 case FT_PIXEL_MODE_MONO:
539 case FT_PIXEL_MODE_GRAY:
540 case FT_PIXEL_MODE_GRAY2:
541 case FT_PIXEL_MODE_GRAY4:
542 case FT_PIXEL_MODE_LCD:
543 case FT_PIXEL_MODE_LCD_V:
544 case FT_PIXEL_MODE_BGRA:
545 {
546 FT_Int pad, old_target_pitch, target_pitch;
547 FT_ULong old_size;
548
549
550 old_target_pitch = target->pitch;
551 if ( old_target_pitch < 0 )
552 old_target_pitch = -old_target_pitch;
553
554 old_size = target->rows * (FT_UInt)old_target_pitch;
555
556 target->pixel_mode = FT_PIXEL_MODE_GRAY;
557 target->rows = source->rows;
558 target->width = source->width;
559
560 pad = 0;
561 if ( alignment > 0 )
562 {
563 pad = (FT_Int)source->width % alignment;
564 if ( pad != 0 )
565 pad = alignment - pad;
566 }
567
568 target_pitch = (FT_Int)source->width + pad;
569
570 if ( target_pitch > 0 &&
571 (FT_ULong)target->rows > FT_ULONG_MAX / (FT_ULong)target_pitch )
572 return FT_THROW( Invalid_Argument );
573
574 if ( FT_QREALLOC( target->buffer,
575 old_size, target->rows * (FT_UInt)target_pitch ) )
576 return error;
577
578 target->pitch = target->pitch < 0 ? -target_pitch : target_pitch;
579 }
580 break;
581
582 default:
583 error = FT_THROW( Invalid_Argument );
584 }
585
586 s = source->buffer;
587 t = target->buffer;
588
589 /* take care of bitmap flow */
590 if ( source->pitch < 0 )
591 s -= source->pitch * (FT_Int)( source->rows - 1 );
592 if ( target->pitch < 0 )
593 t -= target->pitch * (FT_Int)( target->rows - 1 );
594
595 switch ( source->pixel_mode )
596 {
597 case FT_PIXEL_MODE_MONO:
598 {
599 FT_UInt i;
600
601
602 target->num_grays = 2;
603
604 for ( i = source->rows; i > 0; i-- )
605 {
606 FT_Byte* ss = s;
607 FT_Byte* tt = t;
608 FT_UInt j;
609
610
611 /* get the full bytes */
612 for ( j = source->width >> 3; j > 0; j-- )
613 {
614 FT_Int val = ss[0]; /* avoid a byte->int cast on each line */
615
616
617 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 );
618 tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 );
619 tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 );
620 tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 );
621 tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 );
622 tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 );
623 tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 );
624 tt[7] = (FT_Byte)( val & 0x01 );
625
626 tt += 8;
627 ss += 1;
628 }
629
630 /* get remaining pixels (if any) */
631 j = source->width & 7;
632 if ( j > 0 )
633 {
634 FT_Int val = *ss;
635
636
637 for ( ; j > 0; j-- )
638 {
639 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7);
640 val <<= 1;
641 tt += 1;
642 }
643 }
644
645 s += source->pitch;
646 t += target->pitch;
647 }
648 }
649 break;
650
651
652 case FT_PIXEL_MODE_GRAY:
653 case FT_PIXEL_MODE_LCD:
654 case FT_PIXEL_MODE_LCD_V:
655 {
656 FT_UInt width = source->width;
657 FT_UInt i;
658
659
660 target->num_grays = 256;
661
662 for ( i = source->rows; i > 0; i-- )
663 {
664 FT_ARRAY_COPY( t, s, width );
665
666 s += source->pitch;
667 t += target->pitch;
668 }
669 }
670 break;
671
672
673 case FT_PIXEL_MODE_GRAY2:
674 {
675 FT_UInt i;
676
677
678 target->num_grays = 4;
679
680 for ( i = source->rows; i > 0; i-- )
681 {
682 FT_Byte* ss = s;
683 FT_Byte* tt = t;
684 FT_UInt j;
685
686
687 /* get the full bytes */
688 for ( j = source->width >> 2; j > 0; j-- )
689 {
690 FT_Int val = ss[0];
691
692
693 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
694 tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 );
695 tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 );
696 tt[3] = (FT_Byte)( ( val & 0x03 ) );
697
698 ss += 1;
699 tt += 4;
700 }
701
702 j = source->width & 3;
703 if ( j > 0 )
704 {
705 FT_Int val = ss[0];
706
707
708 for ( ; j > 0; j-- )
709 {
710 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
711 val <<= 2;
712 tt += 1;
713 }
714 }
715
716 s += source->pitch;
717 t += target->pitch;
718 }
719 }
720 break;
721
722
723 case FT_PIXEL_MODE_GRAY4:
724 {
725 FT_UInt i;
726
727
728 target->num_grays = 16;
729
730 for ( i = source->rows; i > 0; i-- )
731 {
732 FT_Byte* ss = s;
733 FT_Byte* tt = t;
734 FT_UInt j;
735
736
737 /* get the full bytes */
738 for ( j = source->width >> 1; j > 0; j-- )
739 {
740 FT_Int val = ss[0];
741
742
743 tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 );
744 tt[1] = (FT_Byte)( ( val & 0x0F ) );
745
746 ss += 1;
747 tt += 2;
748 }
749
750 if ( source->width & 1 )
751 tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 );
752
753 s += source->pitch;
754 t += target->pitch;
755 }
756 }
757 break;
758
759
760 case FT_PIXEL_MODE_BGRA:
761 {
762 FT_UInt i;
763
764
765 target->num_grays = 256;
766
767 for ( i = source->rows; i > 0; i-- )
768 {
769 FT_Byte* ss = s;
770 FT_Byte* tt = t;
771 FT_UInt j;
772
773
774 for ( j = source->width; j > 0; j-- )
775 {
776 tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss );
777
778 ss += 4;
779 tt += 1;
780 }
781
782 s += source->pitch;
783 t += target->pitch;
784 }
785 }
786 break;
787
788 default:
789 ;
790 }
791
792 return error;
793 }
794
795
796 /* documentation is in ftbitmap.h */
797
798 FT_EXPORT_DEF( FT_Error )
799 FT_Bitmap_Blend( FT_Library library,
800 const FT_Bitmap* source_,
801 const FT_Vector source_offset_,
802 FT_Bitmap* target,
803 FT_Vector *atarget_offset,
804 FT_Color color )
805 {
806 FT_Error error = FT_Err_Ok;
807 FT_Memory memory;
808
809 FT_Bitmap source_bitmap;
810 const FT_Bitmap* source;
811
812 FT_Vector source_offset;
813 FT_Vector target_offset;
814
815 FT_Bool free_source_bitmap = 0;
816 FT_Bool free_target_bitmap_on_error = 0;
817
818 FT_Pos source_llx, source_lly, source_urx, source_ury;
819 FT_Pos target_llx, target_lly, target_urx, target_ury;
820 FT_Pos final_llx, final_lly, final_urx, final_ury;
821
822 unsigned int final_rows, final_width;
823 long x, y;
824
825
826 if ( !library || !target || !source_ || !atarget_offset )
827 return FT_THROW( Invalid_Argument );
828
829 memory = library->memory;
830
831 if ( !( target->pixel_mode == FT_PIXEL_MODE_NONE ||
832 ( target->pixel_mode == FT_PIXEL_MODE_BGRA &&
833 target->buffer ) ) )
834 return FT_THROW( Invalid_Argument );
835
836 if ( source_->pixel_mode == FT_PIXEL_MODE_NONE )
837 return FT_Err_Ok; /* nothing to do */
838
839 /* pitches must have the same sign */
840 if ( target->pixel_mode == FT_PIXEL_MODE_BGRA &&
841 ( source_->pitch ^ target->pitch ) < 0 )
842 return FT_THROW( Invalid_Argument );
843
844 if ( !( source_->width && source_->rows ) )
845 return FT_Err_Ok; /* nothing to do */
846
847 /* assure integer pixel offsets */
848 source_offset.x = FT_PIX_FLOOR( source_offset_.x );
849 source_offset.y = FT_PIX_FLOOR( source_offset_.y );
850 target_offset.x = FT_PIX_FLOOR( atarget_offset->x );
851 target_offset.y = FT_PIX_FLOOR( atarget_offset->y );
852
853 /* get source bitmap dimensions */
854 source_llx = source_offset.x;
855 if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y )
856 {
857 FT_TRACE5((
858 "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" ));
859 return FT_THROW( Invalid_Argument );
860 }
861 source_lly = source_offset.y - ( source_->rows << 6 );
862
863 if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx )
864 {
865 FT_TRACE5((
866 "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" ));
867 return FT_THROW( Invalid_Argument );
868 }
869 source_urx = source_llx + ( source_->width << 6 );
870 source_ury = source_offset.y;
871
872 /* get target bitmap dimensions */
873 if ( target->width && target->rows )
874 {
875 target_llx = target_offset.x;
876 if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y )
877 {
878 FT_TRACE5((
879 "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" ));
880 return FT_THROW( Invalid_Argument );
881 }
882 target_lly = target_offset.y - ( target->rows << 6 );
883
884 if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx )
885 {
886 FT_TRACE5((
887 "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" ));
888 return FT_THROW( Invalid_Argument );
889 }
890 target_urx = target_llx + ( target->width << 6 );
891 target_ury = target_offset.y;
892 }
893 else
894 {
895 target_llx = FT_LONG_MAX;
896 target_lly = FT_LONG_MAX;
897 target_urx = FT_LONG_MIN;
898 target_ury = FT_LONG_MIN;
899 }
900
901 /* compute final bitmap dimensions */
902 final_llx = FT_MIN( source_llx, target_llx );
903 final_lly = FT_MIN( source_lly, target_lly );
904 final_urx = FT_MAX( source_urx, target_urx );
905 final_ury = FT_MAX( source_ury, target_ury );
906
907 final_width = ( final_urx - final_llx ) >> 6;
908 final_rows = ( final_ury - final_lly ) >> 6;
909
910#ifdef FT_DEBUG_LEVEL_TRACE
911 FT_TRACE5(( "FT_Bitmap_Blend:\n"
912 " source bitmap: (%d, %d) -- (%d, %d); %d x %d\n",
913 source_llx / 64, source_lly / 64,
914 source_urx / 64, source_ury / 64,
915 source_->width, source_->rows ));
916
917 if ( target->width && target->rows )
918 FT_TRACE5(( " target bitmap: (%d, %d) -- (%d, %d); %d x %d\n",
919 target_llx / 64, target_lly / 64,
920 target_urx / 64, target_ury / 64,
921 target->width, target->rows ));
922 else
923 FT_TRACE5(( " target bitmap: empty\n" ));
924
925 FT_TRACE5(( " final bitmap: (%d, %d) -- (%d, %d); %d x %d\n",
926 final_llx / 64, final_lly / 64,
927 final_urx / 64, final_ury / 64,
928 final_width, final_rows ));
929#endif /* FT_DEBUG_LEVEL_TRACE */
930
931 /* for blending, set offset vector of final bitmap */
932 /* temporarily to (0,0) */
933 source_llx -= final_llx;
934 source_lly -= final_lly;
935
936 if ( target->width && target->rows )
937 {
938 target_llx -= final_llx;
939 target_lly -= final_lly;
940 }
941
942 /* set up target bitmap */
943 if ( target->pixel_mode == FT_PIXEL_MODE_NONE )
944 {
945 /* create new empty bitmap */
946 target->width = final_width;
947 target->rows = final_rows;
948 target->pixel_mode = FT_PIXEL_MODE_BGRA;
949 target->pitch = (int)final_width * 4;
950 target->num_grays = 256;
951
952 if ( FT_LONG_MAX / target->pitch < (int)target->rows )
953 {
954 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n",
955 final_width, final_rows ));
956 return FT_THROW( Invalid_Argument );
957 }
958
959 if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) )
960 return error;
961
962 free_target_bitmap_on_error = 1;
963 }
964 else if ( target->width != final_width ||
965 target->rows != final_rows )
966 {
967 /* adjust old bitmap to enlarged size */
968 int pitch, new_pitch;
969
970 unsigned char* buffer = NULL;
971
972
973 pitch = target->pitch;
974 if ( pitch < 0 )
975 pitch = -pitch;
976
977 new_pitch = (int)final_width * 4;
978
979 if ( FT_LONG_MAX / new_pitch < (int)final_rows )
980 {
981 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n",
982 final_width, final_rows ));
983 return FT_THROW( Invalid_Argument );
984 }
985
986 /* TODO: provide an in-buffer solution for large bitmaps */
987 /* to avoid allocation of a new buffer */
988 if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) )
989 goto Error;
990
991 /* copy data to new buffer */
992 x = target_llx >> 6;
993 y = target_lly >> 6;
994
995 /* the bitmap flow is from top to bottom, */
996 /* but y is measured from bottom to top */
997 if ( target->pitch < 0 )
998 {
999 /* XXX */
1000 }
1001 else
1002 {
1003 unsigned char* p =
1004 target->buffer;
1005 unsigned char* q =
1006 buffer +
1007 ( final_rows - y - target->rows ) * new_pitch +
1008 x * 4;
1009 unsigned char* limit_p =
1010 p + pitch * (int)target->rows;
1011
1012
1013 while ( p < limit_p )
1014 {
1015 FT_MEM_COPY( q, p, pitch );
1016
1017 p += pitch;
1018 q += new_pitch;
1019 }
1020 }
1021
1022 FT_FREE( target->buffer );
1023
1024 target->width = final_width;
1025 target->rows = final_rows;
1026
1027 if ( target->pitch < 0 )
1028 target->pitch = -new_pitch;
1029 else
1030 target->pitch = new_pitch;
1031
1032 target->buffer = buffer;
1033 }
1034
1035 /* adjust source bitmap if necessary */
1036 if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY )
1037 {
1038 FT_Bitmap_Init( &source_bitmap );
1039 error = FT_Bitmap_Convert( library, source_, &source_bitmap, 1 );
1040 if ( error )
1041 goto Error;
1042
1043 source = &source_bitmap;
1044 free_source_bitmap = 1;
1045 }
1046 else
1047 source = source_;
1048
1049 /* do blending; the code below returns pre-multiplied channels, */
1050 /* similar to what FreeType gets from `CBDT' tables */
1051 x = source_llx >> 6;
1052 y = source_lly >> 6;
1053
1054 /* the bitmap flow is from top to bottom, */
1055 /* but y is measured from bottom to top */
1056 if ( target->pitch < 0 )
1057 {
1058 /* XXX */
1059 }
1060 else
1061 {
1062 unsigned char* p =
1063 source->buffer;
1064 unsigned char* q =
1065 target->buffer +
1066 ( target->rows - y - source->rows ) * target->pitch +
1067 x * 4;
1068 unsigned char* limit_p =
1069 p + source->pitch * (int)source->rows;
1070
1071
1072 while ( p < limit_p )
1073 {
1074 unsigned char* r = p;
1075 unsigned char* s = q;
1076 unsigned char* limit_r = r + source->width;
1077
1078
1079 while ( r < limit_r )
1080 {
1081 int aa = *r++;
1082 int fa = color.alpha * aa / 255;
1083
1084 int fb = color.blue * fa / 255;
1085 int fg = color.green * fa / 255;
1086 int fr = color.red * fa / 255;
1087
1088 int ba2 = 255 - fa;
1089
1090 int bb = s[0];
1091 int bg = s[1];
1092 int br = s[2];
1093 int ba = s[3];
1094
1095
1096 *s++ = (unsigned char)( bb * ba2 / 255 + fb );
1097 *s++ = (unsigned char)( bg * ba2 / 255 + fg );
1098 *s++ = (unsigned char)( br * ba2 / 255 + fr );
1099 *s++ = (unsigned char)( ba * ba2 / 255 + fa );
1100 }
1101
1102 p += source->pitch;
1103 q += target->pitch;
1104 }
1105 }
1106
1107 atarget_offset->x = final_llx;
1108 atarget_offset->y = final_lly + ( final_rows << 6 );
1109
1110 Error:
1111 if ( error && free_target_bitmap_on_error )
1112 FT_Bitmap_Done( library, target );
1113
1114 if ( free_source_bitmap )
1115 FT_Bitmap_Done( library, &source_bitmap );
1116
1117 return error;
1118 }
1119
1120
1121 /* documentation is in ftbitmap.h */
1122
1123 FT_EXPORT_DEF( FT_Error )
1124 FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot )
1125 {
1126 if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP &&
1127 !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
1128 {
1129 FT_Bitmap bitmap;
1130 FT_Error error;
1131
1132
1133 FT_Bitmap_Init( &bitmap );
1134 error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap );
1135 if ( error )
1136 return error;
1137
1138 slot->bitmap = bitmap;
1139 slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
1140 }
1141
1142 return FT_Err_Ok;
1143 }
1144
1145
1146 /* documentation is in ftbitmap.h */
1147
1148 FT_EXPORT_DEF( FT_Error )
1149 FT_Bitmap_Done( FT_Library library,
1150 FT_Bitmap *bitmap )
1151 {
1152 FT_Memory memory;
1153
1154
1155 if ( !library )
1156 return FT_THROW( Invalid_Library_Handle );
1157
1158 if ( !bitmap )
1159 return FT_THROW( Invalid_Argument );
1160
1161 memory = library->memory;
1162
1163 FT_FREE( bitmap->buffer );
1164 *bitmap = null_bitmap;
1165
1166 return FT_Err_Ok;
1167 }
1168
1169
1170/* END */
1171