swfmill 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. data/.document +5 -0
  2. data/.gitignore +23 -0
  3. data/.swfmill +240 -0
  4. data/LICENSE +340 -0
  5. data/README.rdoc +37 -0
  6. data/Rakefile +59 -0
  7. data/VERSION +1 -0
  8. data/ext/.gitignore +5 -0
  9. data/ext/extconf.rb +86 -0
  10. data/ext/swfmill/.gitignore +27 -0
  11. data/ext/swfmill/AUTHORS +9 -0
  12. data/ext/swfmill/COPYING +340 -0
  13. data/ext/swfmill/Makefile.am +14 -0
  14. data/ext/swfmill/Makefile.in +635 -0
  15. data/ext/swfmill/NEWS +189 -0
  16. data/ext/swfmill/README +170 -0
  17. data/ext/swfmill/TODO +33 -0
  18. data/ext/swfmill/aclocal.m4 +7712 -0
  19. data/ext/swfmill/autogen.sh +7 -0
  20. data/ext/swfmill/compile +142 -0
  21. data/ext/swfmill/config.guess +1516 -0
  22. data/ext/swfmill/config.sub +1626 -0
  23. data/ext/swfmill/configure +21868 -0
  24. data/ext/swfmill/configure.ac +55 -0
  25. data/ext/swfmill/depcomp +589 -0
  26. data/ext/swfmill/install-sh +519 -0
  27. data/ext/swfmill/ltmain.sh +6964 -0
  28. data/ext/swfmill/missing +367 -0
  29. data/ext/swfmill/src/Geom.cpp +107 -0
  30. data/ext/swfmill/src/Geom.h +100 -0
  31. data/ext/swfmill/src/Makefile.am +86 -0
  32. data/ext/swfmill/src/Makefile.in +1025 -0
  33. data/ext/swfmill/src/SWF.h +11941 -0
  34. data/ext/swfmill/src/SWFAction.cpp +41 -0
  35. data/ext/swfmill/src/SWFAction.h +19 -0
  36. data/ext/swfmill/src/SWFBasic.h +7 -0
  37. data/ext/swfmill/src/SWFFile.cpp +406 -0
  38. data/ext/swfmill/src/SWFFile.h +34 -0
  39. data/ext/swfmill/src/SWFFilter.cpp +25 -0
  40. data/ext/swfmill/src/SWFFilter.h +15 -0
  41. data/ext/swfmill/src/SWFGlyphList.cpp +262 -0
  42. data/ext/swfmill/src/SWFGlyphList.h +34 -0
  43. data/ext/swfmill/src/SWFIdItem.h +85 -0
  44. data/ext/swfmill/src/SWFIdItems.h +16 -0
  45. data/ext/swfmill/src/SWFItem.cpp +235 -0
  46. data/ext/swfmill/src/SWFItem.h +60 -0
  47. data/ext/swfmill/src/SWFList.h +179 -0
  48. data/ext/swfmill/src/SWFReader.cpp +352 -0
  49. data/ext/swfmill/src/SWFReader.h +73 -0
  50. data/ext/swfmill/src/SWFShapeItem.cpp +220 -0
  51. data/ext/swfmill/src/SWFShapeItem.h +45 -0
  52. data/ext/swfmill/src/SWFShapeMaker.cpp +401 -0
  53. data/ext/swfmill/src/SWFShapeMaker.h +128 -0
  54. data/ext/swfmill/src/SWFTag.cpp +49 -0
  55. data/ext/swfmill/src/SWFTag.h +20 -0
  56. data/ext/swfmill/src/SWFTrait.cpp +35 -0
  57. data/ext/swfmill/src/SWFTrait.h +22 -0
  58. data/ext/swfmill/src/SWFWriter.cpp +312 -0
  59. data/ext/swfmill/src/SWFWriter.h +84 -0
  60. data/ext/swfmill/src/base64.c +110 -0
  61. data/ext/swfmill/src/base64.h +15 -0
  62. data/ext/swfmill/src/codegen/Makefile.am +15 -0
  63. data/ext/swfmill/src/codegen/Makefile.in +346 -0
  64. data/ext/swfmill/src/codegen/basic.xsl +45 -0
  65. data/ext/swfmill/src/codegen/basics.xsl +235 -0
  66. data/ext/swfmill/src/codegen/dumper.xsl +109 -0
  67. data/ext/swfmill/src/codegen/header.xsl +131 -0
  68. data/ext/swfmill/src/codegen/mk.xsl +26 -0
  69. data/ext/swfmill/src/codegen/parser.xsl +196 -0
  70. data/ext/swfmill/src/codegen/parsexml.xsl +312 -0
  71. data/ext/swfmill/src/codegen/size.xsl +189 -0
  72. data/ext/swfmill/src/codegen/source.xml +2197 -0
  73. data/ext/swfmill/src/codegen/writer.xsl +190 -0
  74. data/ext/swfmill/src/codegen/writexml.xsl +138 -0
  75. data/ext/swfmill/src/swfmill.cpp +482 -0
  76. data/ext/swfmill/src/swft/Makefile.am +55 -0
  77. data/ext/swfmill/src/swft/Makefile.in +717 -0
  78. data/ext/swfmill/src/swft/Parser.cpp +76 -0
  79. data/ext/swfmill/src/swft/Parser.h +37 -0
  80. data/ext/swfmill/src/swft/SVGAttributeParser.cpp +78 -0
  81. data/ext/swfmill/src/swft/SVGAttributeParser.h +35 -0
  82. data/ext/swfmill/src/swft/SVGColor.cpp +116 -0
  83. data/ext/swfmill/src/swft/SVGColor.h +37 -0
  84. data/ext/swfmill/src/swft/SVGColors.h +167 -0
  85. data/ext/swfmill/src/swft/SVGGradient.cpp +258 -0
  86. data/ext/swfmill/src/swft/SVGGradient.h +81 -0
  87. data/ext/swfmill/src/swft/SVGPathParser.cpp +155 -0
  88. data/ext/swfmill/src/swft/SVGPathParser.h +126 -0
  89. data/ext/swfmill/src/swft/SVGPointsParser.cpp +51 -0
  90. data/ext/swfmill/src/swft/SVGPointsParser.h +25 -0
  91. data/ext/swfmill/src/swft/SVGStyle.cpp +181 -0
  92. data/ext/swfmill/src/swft/SVGStyle.h +80 -0
  93. data/ext/swfmill/src/swft/SVGTransformParser.cpp +72 -0
  94. data/ext/swfmill/src/swft/SVGTransformParser.h +32 -0
  95. data/ext/swfmill/src/swft/readpng.c +305 -0
  96. data/ext/swfmill/src/swft/readpng.h +92 -0
  97. data/ext/swfmill/src/swft/swft.cpp +251 -0
  98. data/ext/swfmill/src/swft/swft.h +64 -0
  99. data/ext/swfmill/src/swft/swft_document.cpp +57 -0
  100. data/ext/swfmill/src/swft/swft_import.cpp +38 -0
  101. data/ext/swfmill/src/swft/swft_import_binary.cpp +82 -0
  102. data/ext/swfmill/src/swft/swft_import_jpeg.cpp +255 -0
  103. data/ext/swfmill/src/swft/swft_import_mp3.cpp +268 -0
  104. data/ext/swfmill/src/swft/swft_import_png.cpp +231 -0
  105. data/ext/swfmill/src/swft/swft_import_ttf.cpp +519 -0
  106. data/ext/swfmill/src/swft/swft_import_wav.cpp +255 -0
  107. data/ext/swfmill/src/swft/swft_path.cpp +178 -0
  108. data/ext/swfmill/src/xslt/Makefile.am +51 -0
  109. data/ext/swfmill/src/xslt/Makefile.in +536 -0
  110. data/ext/swfmill/src/xslt/README +19 -0
  111. data/ext/swfmill/src/xslt/assemble.xsl +38 -0
  112. data/ext/swfmill/src/xslt/simple-deprecated.xslt +62 -0
  113. data/ext/swfmill/src/xslt/simple-elements.xslt +627 -0
  114. data/ext/swfmill/src/xslt/simple-import.xslt +565 -0
  115. data/ext/swfmill/src/xslt/simple-svg.xslt +383 -0
  116. data/ext/swfmill/src/xslt/simple-tools.xslt +255 -0
  117. data/ext/swfmill/src/xslt/simple.cpp +1686 -0
  118. data/ext/swfmill/src/xslt/simple.xml +7 -0
  119. data/ext/swfmill/src/xslt/xslt.h +7 -0
  120. data/ext/swfmill/test/Makefile.am +1 -0
  121. data/ext/swfmill/test/Makefile.in +490 -0
  122. data/ext/swfmill/test/xml/Makefile.am +20 -0
  123. data/ext/swfmill/test/xml/Makefile.in +353 -0
  124. data/ext/swfmill/test/xml/test-xml +21 -0
  125. data/ext/swfmill_ext.cc +375 -0
  126. data/lib/swfmill.rb +30 -0
  127. data/spec/data/swfmill-banner1.swf +0 -0
  128. data/spec/spec.opts +1 -0
  129. data/spec/spec_helper.rb +14 -0
  130. data/spec/swfmill_spec.rb +125 -0
  131. metadata +206 -0
@@ -0,0 +1,231 @@
1
+ #include <libxslt/extensions.h>
2
+ #include <libxslt/xsltutils.h>
3
+ #include <libxml/xpathInternals.h>
4
+ #include <libxslt/variables.h>
5
+ #include "swft.h"
6
+ #include <sys/types.h>
7
+ #include <sys/stat.h>
8
+ #include <cstring>
9
+ #include "readpng.h"
10
+ #include <zlib.h>
11
+
12
+ #define TMP_STRLEN 0xff
13
+
14
+ // outLength should contain the allocated size,
15
+ // will be updated with the actual size
16
+ bool compress( unsigned char *inputBuffer, int inLength, unsigned char *outputBuffer, int *outLength ) {
17
+ z_stream stream;
18
+ int status, count;
19
+
20
+ stream.avail_in = inLength;
21
+ stream.next_in = inputBuffer;
22
+ stream.next_out = outputBuffer;
23
+ stream.zalloc = (alloc_func) NULL;
24
+ stream.zfree = (free_func) NULL;
25
+ stream.opaque = (voidpf) 0;
26
+ stream.avail_out = *outLength;
27
+
28
+ status = deflateInit( &stream, Z_BEST_COMPRESSION );
29
+ if( status != Z_OK ) {
30
+ fprintf( stderr, "ERROR: compressing PNG (1): %s\n", stream.msg );
31
+ return false;
32
+ }
33
+
34
+ while( true ) {
35
+ if( stream.avail_in == 0 ) break;
36
+
37
+ status = deflate( &stream, Z_NO_FLUSH );
38
+
39
+ if( status != Z_OK ) {
40
+ fprintf( stderr, "ERROR: compressing PNG (2): %s\n", stream.msg );
41
+ return false;
42
+ }
43
+ }
44
+
45
+ do {
46
+ status = deflate( &stream, Z_FINISH );
47
+ } while( status == Z_OK );
48
+
49
+ if( status != Z_STREAM_END ) {
50
+ fprintf( stderr, "ERROR: compressing PNG (3): %s\n", stream.msg );
51
+ return false;
52
+ }
53
+
54
+ status = deflateEnd(&stream);
55
+
56
+ if( status != Z_OK ) {
57
+ fprintf( stderr, "ERROR: compressing PNG (4): %s\n", stream.msg );
58
+ return false;
59
+ }
60
+
61
+ *outLength -= stream.avail_out;
62
+ return true;
63
+ }
64
+
65
+
66
+ void swft_import_png( xmlXPathParserContextPtr ctx, int nargs ) {
67
+ xsltTransformContextPtr tctx;
68
+ xmlChar *filename;
69
+ xsltDocumentPtr xsltdoc;
70
+ xmlDocPtr doc = NULL;
71
+ xmlNodePtr node;
72
+ xmlXPathObjectPtr obj;
73
+ char tmp[TMP_STRLEN];
74
+ png_colorp palette;
75
+ int n_pal;
76
+
77
+ xmlXPathStringFunction(ctx, 1);
78
+ if (ctx->value->type != XPATH_STRING) {
79
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
80
+ "swft:import-png() : invalid arg expecting a string\n");
81
+ ctx->error = XPATH_INVALID_TYPE;
82
+ return;
83
+ }
84
+ obj = valuePop(ctx);
85
+ if (obj->stringval == NULL) {
86
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
87
+ return;
88
+ }
89
+
90
+ tctx = xsltXPathGetTransformContext(ctx);
91
+
92
+ filename = swft_get_filename(obj->stringval);
93
+
94
+ bool quiet = true;
95
+ xmlXPathObjectPtr quietObj = xsltVariableLookup( tctx, (const xmlChar*)"quiet", NULL );
96
+ if( quietObj && quietObj->stringval ) { quiet = !strcmp("true",(const char*)quietObj->stringval ); };
97
+
98
+
99
+ FILE *fp = fopen( (const char *)filename, "rb" );
100
+ if( !fp ) {
101
+ xsltTransformError(xsltXPathGetTransformContext(ctx), NULL, NULL,
102
+ "swft:import-png() : failed to read file '%s'\n", (const char *)filename);
103
+ valuePush(ctx, xmlXPathNewNodeSet(NULL));
104
+ return;
105
+ }
106
+
107
+ doc = xmlNewDoc( (const xmlChar *)"1.0");
108
+ doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar *)"png", NULL );
109
+ node = doc->xmlRootNode;
110
+
111
+ swft_addFileName( node, (const char *)filename );
112
+
113
+
114
+ // add data
115
+ rewind(fp);
116
+ unsigned char *data, *compressed;
117
+ unsigned long w, h, rowbytes;
118
+ int channels;
119
+ int compressed_size;
120
+ int format = 5;
121
+ int data_size = 0;
122
+ if( !fp ) goto fail;
123
+
124
+ if( readpng_init( fp, &w, &h ) ) goto fail;
125
+
126
+ // add w/h
127
+ snprintf(tmp,TMP_STRLEN,"%i", w);
128
+ xmlSetProp( node, (const xmlChar *)"width", (const xmlChar *)&tmp );
129
+ snprintf(tmp,TMP_STRLEN,"%i", h);
130
+ xmlSetProp( node, (const xmlChar *)"height", (const xmlChar *)&tmp );
131
+
132
+ data = readpng_get_image( 2.2, &channels, &rowbytes, &palette, &n_pal );
133
+
134
+ if( !quiet ) {
135
+ fprintf(stderr,"Importing PNG: '%s' (%i bit/pixel)\n", filename, (rowbytes*8)/w );
136
+ }
137
+
138
+ if( channels == 4 && rowbytes == (4*w) ) {
139
+ int c;
140
+ float a;
141
+ unsigned char r,g,b;
142
+ for( int i=0; i<w*h*4; i+=4 ) {
143
+ a = data[i+3]/255.0;
144
+ r = (unsigned char)((data[i+0])*a);
145
+ g = (unsigned char)((data[i+1])*a);
146
+ b = (unsigned char)((data[i+2])*a);
147
+ data[i] = data[i+3];
148
+ data[i+1] = r;
149
+ data[i+2] = g;
150
+ data[i+3] = b;
151
+ }
152
+ data_size = w*h*4;
153
+ } else if( channels == 3 && rowbytes == (3*w) ) {
154
+ unsigned char *rgba = new unsigned char[ w*h*4 ];
155
+
156
+ for( int i=0; i<w*h; i++ ) {
157
+ rgba[i*4] = 0xff;
158
+ rgba[(i*4)+3] = data[(i*3)+2];
159
+ rgba[(i*4)+2] = data[(i*3)+1];
160
+ rgba[(i*4)+1] = data[(i*3)];
161
+ }
162
+ data = rgba;
163
+ data_size = w*h*4;
164
+ } else if( channels == 1 && rowbytes == w ) {
165
+ unsigned char *img_data = data;
166
+ format = 3;
167
+ int bpr = rowbytes;
168
+ bpr += (rowbytes % 4) ? 4 - (rowbytes % 4) : 0;
169
+ if( n_pal ) {
170
+ data_size = (4*n_pal) + (bpr*h);
171
+ data = new unsigned char[ data_size ];
172
+ for( int i=0; i<n_pal; i++ ) {
173
+ unsigned char *entry = &data[(i*4)];
174
+ entry[2] = palette[i].blue;
175
+ entry[1] = palette[i].green;
176
+ entry[0] = palette[i].red;
177
+ entry[3] = 0xff;
178
+ }
179
+ } else {
180
+ n_pal = 0xff;
181
+ data_size = (4*n_pal) + (bpr*h);
182
+ data = new unsigned char[ data_size ];
183
+ for( int i=0; i<n_pal; i++ ) {
184
+ unsigned char *entry = &data[(i*4)];
185
+ entry[2] = i;
186
+ entry[1] = i;
187
+ entry[0] = i;
188
+ entry[3] = 0xff;
189
+ }
190
+ }
191
+
192
+ /* copy row by row with 32bit alignment */
193
+ unsigned char *dst = &data[ (4*n_pal) ];
194
+ unsigned char *src = img_data;
195
+ memset( dst, 0, bpr*h );
196
+ for( int y=0; y<h; y++ ) {
197
+ memcpy( dst, src, rowbytes );
198
+ dst += bpr;
199
+ src += rowbytes;
200
+ }
201
+
202
+ snprintf(tmp,TMP_STRLEN,"%i", n_pal-1 );
203
+ xmlSetProp( node, (const xmlChar *)"n_colormap", (const xmlChar *)&tmp );
204
+ } else {
205
+ fprintf( stderr, "WARNING: can only import 8bit palette, 24 or 32bit RGB(A) PNGs (%s has %i channels, rowstride %i)\n", filename, channels, rowbytes );
206
+ goto fail;
207
+ }
208
+
209
+ // format is 5 for RGB(A), 3 for palette (4 for 16bit, unused)
210
+ snprintf(tmp,TMP_STRLEN,"%i", format );
211
+ xmlSetProp( node, (const xmlChar *)"format", (const xmlChar *)&tmp );
212
+
213
+ compressed_size = data_size;
214
+ if( compressed_size < 64 ) compressed_size = 64;
215
+ compressed = new unsigned char[ compressed_size ];
216
+ if( compress( data, data_size, compressed, &compressed_size ) ) {
217
+ swft_addData( node, (char*)compressed, compressed_size );
218
+ valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) );
219
+ }
220
+
221
+ delete compressed;
222
+ readpng_cleanup( true );
223
+ if( fp ) fclose(fp);
224
+ return;
225
+
226
+ fail:
227
+ readpng_cleanup( true );
228
+ if( fp ) fclose(fp);
229
+ fprintf( stderr, "WARNING: could not import %s\n", filename );
230
+ return;
231
+ }
@@ -0,0 +1,519 @@
1
+ #include <libxslt/extensions.h>
2
+ #include <libxslt/xsltutils.h>
3
+ #include <libxslt/variables.h>
4
+ #include <libxml/xpathInternals.h>
5
+ #include "swft.h"
6
+ #include <sys/types.h>
7
+ #include <sys/stat.h>
8
+ #include <cstring>
9
+ #include <cmath>
10
+
11
+ #include "SWF.h"
12
+ #include <ft2build.h>
13
+ #include FT_FREETYPE_H
14
+ #include FT_OUTLINE_H
15
+ #include "SWFShapeMaker.h"
16
+
17
+ using namespace SWF;
18
+
19
+ #define TMP_STRLEN 0xff
20
+
21
+ int moveTo( const FT_Vector *to, void *shaper ) {
22
+ ((ShapeMaker*)shaper)->setup( to->x, to->y );
23
+
24
+ return 0;
25
+ }
26
+
27
+ int lineTo( const FT_Vector *to, void *shaper ) {
28
+ ((ShapeMaker*)shaper)->lineTo( to->x, to->y );
29
+
30
+ return 0;
31
+ }
32
+
33
+ int conicTo( const FT_Vector *control, const FT_Vector *to, void *shaper ) {
34
+ ((ShapeMaker*)shaper)->curveTo( control->x, control->y, to->x, to->y );
35
+
36
+ return 0;
37
+ }
38
+
39
+ int cubicTo( const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *shaper ) {
40
+ fprintf(stderr,"ERROR: cubic beziers in fonts are not yet implemented.\n");
41
+
42
+ return 0;
43
+ }
44
+
45
+ FT_Outline_Funcs decomposeFunctions = {
46
+ (FT_Outline_MoveToFunc)moveTo,
47
+ (FT_Outline_LineToFunc)lineTo,
48
+ (FT_Outline_ConicToFunc)conicTo,
49
+ (FT_Outline_CubicToFunc)cubicTo,
50
+ 0,
51
+ 0
52
+ };
53
+
54
+ bool emptyGlyph( FT_Face face, FT_ULong wc ) {
55
+ return( wc != 32 && face->glyph->outline.n_points == 0 );
56
+ }
57
+
58
+ int compareGlyphs( const void *a, const void *b ) {
59
+ int _a = *(int*)a;
60
+ int _b = *(int*)b;
61
+ return( _a - _b );
62
+ }
63
+
64
+ void importDefineFont2( DefineFont2 *tag, const char *filename, const char *fontname, const xmlChar *glyphs_xml, Context *ctx, swft_ctx *swftctx, int offset ) {
65
+ FT_Library swfft_library;
66
+ FT_Face face;
67
+ int error;
68
+ FT_UInt glyph_index;
69
+ FT_ULong character;
70
+ FT_Outline *outline;
71
+ int *glyphs = NULL;
72
+ int i=0;
73
+ char *font_ascentmap;
74
+
75
+ GlyphList *glyphList = tag->getglyphs();
76
+ List<Short>* advance = tag->getadvance();
77
+ List<Rectangle>* bounds = tag->getbounds();
78
+ List<WideKerning>* kernings = tag->getwideKerning();
79
+ // NYI: kerning
80
+
81
+ GlyphShape *shape;
82
+ int nGlyphs, glyph;
83
+
84
+ if( FT_Init_FreeType( &swfft_library ) ) {
85
+ fprintf( stderr, "WARNING: could not initialize FreeType\n" );
86
+ goto fail;
87
+ }
88
+
89
+ error = FT_New_Face( swfft_library, filename, 0, &face );
90
+ if( error ) {
91
+ fprintf( stderr, "WARNING: FreeType does not like %s\n", filename );
92
+ goto fail;
93
+ }
94
+
95
+ if( face->num_faces > 1 ) {
96
+ fprintf( stderr, "WARNING: %s contains %i faces, but only the first is imported.\n", filename, face->num_faces );
97
+ }
98
+
99
+ FT_Set_Char_Size(face, (1024<<6), (1024<<6), 72, 72);
100
+
101
+ // count availably glyphs, yes we have to load them to check if they're empty, sorry.
102
+ nGlyphs = 0;
103
+ if( !glyphs_xml ) {
104
+ if( (character = FT_Get_First_Char( face, &glyph_index )) != 0 ) nGlyphs++;
105
+ while( (character = FT_Get_Next_Char( face, character, &glyph_index )) != 0 ) {
106
+ if( FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_BITMAP ) ) {
107
+ fprintf( stderr, "WARNING: cannot load glyph %i ('%c') from %s.\n", character, character, filename );
108
+ goto fail;
109
+ }
110
+ if( face->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) {
111
+ fprintf( stderr, "WARNING: %s seems to be a bitmap font.\n", filename );
112
+ goto fail;
113
+ }
114
+ //if( !emptyGlyph( face, character ) )
115
+ nGlyphs++;
116
+ }
117
+
118
+ glyphs = new int[nGlyphs+1];
119
+ i=0;
120
+ if( (character = FT_Get_First_Char( face, &glyph_index )) != 0 ) glyphs[i++] = character;
121
+ while( (character = FT_Get_Next_Char( face, character, &glyph_index )) != 0 ) {
122
+ //if( !emptyGlyph( face, character ) )
123
+ glyphs[i++] = character;
124
+ }
125
+
126
+ } else {
127
+ int nGlyphs_ = xmlUTF8Strlen( glyphs_xml );
128
+ glyphs = new int[nGlyphs_];
129
+ int len=0, idx=0;
130
+ const unsigned char *str;
131
+
132
+ for( int i=0; i<nGlyphs_; i++ ) {
133
+ str = (const unsigned char *)&glyphs_xml[idx];
134
+ len=4;
135
+ glyphs[i]=xmlGetUTF8Char( str, &len )-offset;
136
+ idx+=len;
137
+ }
138
+
139
+ // sort the list of glyphs
140
+ qsort( glyphs, nGlyphs_, sizeof(int), compareGlyphs );
141
+
142
+ nGlyphs = nGlyphs_;
143
+ }
144
+
145
+ glyphList->allocate( nGlyphs );
146
+ tag->setglyphCount( nGlyphs );
147
+
148
+ tag->sethasLayout( 1 );
149
+
150
+ #define SCALING_FACTOR ((int)1024)
151
+
152
+ tag->setascent( 1+((SCALING_FACTOR * face->ascender) / face->units_per_EM) );
153
+ tag->setdescent( 1+((SCALING_FACTOR * labs(face->descender)) / face->units_per_EM) );
154
+ tag->setleading( 0 ) ;// (1+(SCALING_FACTOR * face->ascender) / face->units_per_EM) + (1+(SCALING_FACTOR * labs(face->descender)) / face->units_per_EM) );
155
+ //1+(SCALING_FACTOR * face->height) / face->units_per_EM );
156
+
157
+ tag->setwideGlyphOffsets( 1 );
158
+ tag->setwideMap( 1 );
159
+
160
+ if( face->style_flags & FT_STYLE_FLAG_ITALIC ) tag->setitalic(true);
161
+ if( face->style_flags & FT_STYLE_FLAG_BOLD ) tag->setbold(true);
162
+ if( !fontname ) fontname = face->family_name;
163
+ tag->setname( strdup(fontname) );
164
+
165
+ if( !ctx->quiet ) {
166
+ fprintf( stderr, "Importing TTF: '%s' - '%s'%s%s (%i glyphs) charcode offset %i\n", filename, fontname,
167
+ face->style_flags & FT_STYLE_FLAG_BOLD ? " bold" : "",
168
+ face->style_flags & FT_STYLE_FLAG_ITALIC ? " italic" : "",
169
+ nGlyphs, offset );
170
+ }
171
+
172
+ for( glyph=0; glyph<nGlyphs; glyph++ ) {
173
+
174
+ character = glyphs[glyph];
175
+ glyph_index = FT_Get_Char_Index( face, character );
176
+
177
+ if( FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_BITMAP ) ) {
178
+ fprintf( stderr, "WARNING: cannot load glyph %i ('%c') from %s.\n", character, character, filename );
179
+ goto fail;
180
+ }
181
+
182
+ if( face->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) {
183
+ fprintf( stderr, "WARNING: %s seems to be a bitmap font.\n", filename );
184
+ goto fail;
185
+ }
186
+
187
+ outline = &face->glyph->outline;
188
+ // fprintf(stderr,"%i importing glyph %i ('%c') of %s (advance %i, %i points)\n", glyph, character, character, filename, face->glyph->advance.x, outline->n_points );
189
+
190
+ Short *adv = new Short();
191
+ adv->setvalue( (short)(ceil(1+(face->glyph->advance.x >> 6))) );
192
+ advance->append(adv);
193
+
194
+ glyphList->setMapN(glyph, character+offset);
195
+ shape = glyphList->getShapeN(glyph);
196
+ ShapeMaker shaper( shape->getedges(), (1.0/64), -(1.0/64), 0, 0 );
197
+ shaper.setStyle( 1, -1, -1 );
198
+
199
+ FT_Outline_Decompose( outline, &decomposeFunctions, &shaper );
200
+
201
+ shaper.finish();
202
+
203
+ Rectangle *r = new Rectangle();
204
+
205
+ Rect rect = shaper.getBounds();
206
+ r->setleft( (int)rect.left );
207
+ r->settop( (int)rect.top );
208
+ r->setright( (int)rect.right );
209
+ r->setbottom( (int)rect.bottom );
210
+
211
+ r->setbits( SWFMaxBitsNeeded( true, 3, r->gettop(), r->getright(), r->getbottom() ) );
212
+ bounds->append(r);
213
+ }
214
+
215
+ if( FT_HAS_KERNING(face) ) {
216
+ FT_Vector vec;
217
+ int l, r;
218
+ for( int left=0; left<nGlyphs; left++ ) {
219
+ for( int right=0; right<nGlyphs; right++ ) {
220
+ l = FT_Get_Char_Index( face, glyphs[left] );
221
+ r = FT_Get_Char_Index( face, glyphs[right] );
222
+ if( !FT_Get_Kerning( face, l, r, FT_KERNING_DEFAULT, &vec ) ) {
223
+ if( vec.x ) {
224
+ // fprintf(stderr,"------ %i -> %i: %i\n", glyphs[left], glyphs[right], vec.x );
225
+
226
+ WideKerning *kern = new WideKerning();
227
+ kern->seta( glyphs[left] );
228
+ kern->setb( glyphs[right] );
229
+ kern->setadjustment( (short)(floor(vec.x >> 6)) );
230
+ kernings->append(kern);
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ if( glyphs ) delete glyphs;
238
+
239
+ // hacky: store the ascent in the idmap.
240
+ font_ascentmap = new char[0xff];
241
+ snprintf( font_ascentmap, 0xff, "%s_ascent", fontname );
242
+ swftctx->setMap( font_ascentmap, 1+(SCALING_FACTOR * face->ascender) / face->units_per_EM );
243
+ delete font_ascentmap;
244
+ // fprintf( stderr, "StoreAscent: %s %i\n", fontname, 1+(SCALING_FACTOR * face->ascender) / face->units_per_EM );
245
+
246
+ return;
247
+
248
+ fail:
249
+ fprintf( stderr, "WARNING: could not import %s\n", filename );
250
+ return;
251
+ }
252
+
253
+ void importDefineFont3( DefineFont3 *tag, const char *filename, const char *fontname, const xmlChar *glyphs_xml, Context *ctx, swft_ctx *swftctx, int offset ) {
254
+ FT_Library swfft_library;
255
+ FT_Face face;
256
+ int error;
257
+ FT_UInt glyph_index;
258
+ FT_ULong character;
259
+ FT_Outline *outline;
260
+ int *glyphs = NULL;
261
+ int i=0;
262
+ char *font_ascentmap;
263
+
264
+ GlyphList *glyphList = tag->getglyphs();
265
+ List<Short>* advance = tag->getadvance();
266
+ List<Rectangle>* bounds = tag->getbounds();
267
+ List<WideKerning>* kernings = tag->getwideKerning();
268
+ // NYI: kerning
269
+
270
+ GlyphShape *shape;
271
+ int nGlyphs, glyph;
272
+
273
+ if( FT_Init_FreeType( &swfft_library ) ) {
274
+ fprintf( stderr, "WARNING: could not initialize FreeType\n" );
275
+ goto fail;
276
+ }
277
+
278
+ error = FT_New_Face( swfft_library, filename, 0, &face );
279
+ if( error ) {
280
+ fprintf( stderr, "WARNING: FreeType does not like %s\n", filename );
281
+ goto fail;
282
+ }
283
+
284
+ if( face->num_faces > 1 ) {
285
+ fprintf( stderr, "WARNING: %s contains %i faces, but only the first is imported.\n", filename, face->num_faces );
286
+ }
287
+
288
+ FT_Set_Char_Size(face, (1024<<6) * 20, (1024<<6) * 20, 72, 72);
289
+
290
+ // count availably glyphs, yes we have to load them to check if they're empty, sorry.
291
+ nGlyphs = 0;
292
+ if( !glyphs_xml ) {
293
+ if( (character = FT_Get_First_Char( face, &glyph_index )) != 0 ) nGlyphs++;
294
+ while( (character = FT_Get_Next_Char( face, character, &glyph_index )) != 0 ) {
295
+ if( FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_BITMAP ) ) {
296
+ fprintf( stderr, "WARNING: cannot load glyph %i ('%c') from %s.\n", character, character, filename );
297
+ goto fail;
298
+ }
299
+ if( face->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) {
300
+ fprintf( stderr, "WARNING: %s seems to be a bitmap font.\n", filename );
301
+ goto fail;
302
+ }
303
+ //if( !emptyGlyph( face, character ) )
304
+ nGlyphs++;
305
+ }
306
+
307
+ glyphs = new int[nGlyphs+1];
308
+ i=0;
309
+ if( (character = FT_Get_First_Char( face, &glyph_index )) != 0 ) glyphs[i++] = character;
310
+ while( (character = FT_Get_Next_Char( face, character, &glyph_index )) != 0 ) {
311
+ //if( !emptyGlyph( face, character ) )
312
+ glyphs[i++] = character;
313
+ }
314
+
315
+ } else {
316
+ int nGlyphs_ = xmlUTF8Strlen( glyphs_xml );
317
+ glyphs = new int[nGlyphs_];
318
+ int len=0, idx=0;
319
+ const unsigned char *str;
320
+
321
+ for( int i=0; i<nGlyphs_; i++ ) {
322
+ str = (const unsigned char *)&glyphs_xml[idx];
323
+ len=4;
324
+ glyphs[i]=xmlGetUTF8Char( str, &len )-offset;
325
+ idx+=len;
326
+ }
327
+
328
+ // sort the list of glyphs
329
+ qsort( glyphs, nGlyphs_, sizeof(int), compareGlyphs );
330
+
331
+ nGlyphs = nGlyphs_;
332
+ }
333
+
334
+ glyphList->allocate( nGlyphs );
335
+ tag->setglyphCount( nGlyphs );
336
+
337
+ tag->sethasLayout( 1 );
338
+
339
+ #define SCALING_FACTOR ((int)1024)
340
+
341
+ tag->setascent( (1+((SCALING_FACTOR * face->ascender) / face->units_per_EM)) * 20 );
342
+ tag->setdescent( (1+((SCALING_FACTOR * labs(face->descender)) / face->units_per_EM)) * 20 );
343
+ tag->setleading( 0 ) ;// (1+(SCALING_FACTOR * face->ascender) / face->units_per_EM) + (1+(SCALING_FACTOR * labs(face->descender)) / face->units_per_EM) );
344
+ //1+(SCALING_FACTOR * face->height) / face->units_per_EM );
345
+
346
+ tag->setwideGlyphOffsets( 1 );
347
+ tag->setwideMap( 1 );
348
+
349
+ if( face->style_flags & FT_STYLE_FLAG_ITALIC ) tag->setitalic(true);
350
+ if( face->style_flags & FT_STYLE_FLAG_BOLD ) tag->setbold(true);
351
+ if( !fontname ) fontname = face->family_name;
352
+ tag->setname( strdup(fontname) );
353
+
354
+ if( !ctx->quiet ) {
355
+ fprintf( stderr, "Importing TTF: '%s' - '%s'%s%s (%i glyphs) charcode offset %i\n", filename, fontname,
356
+ face->style_flags & FT_STYLE_FLAG_BOLD ? " bold" : "",
357
+ face->style_flags & FT_STYLE_FLAG_ITALIC ? " italic" : "",
358
+ nGlyphs, offset );
359
+ }
360
+
361
+ for( glyph=0; glyph<nGlyphs; glyph++ ) {
362
+
363
+ character = glyphs[glyph];
364
+ glyph_index = FT_Get_Char_Index( face, character );
365
+
366
+ if( FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_BITMAP ) ) {
367
+ fprintf( stderr, "WARNING: cannot load glyph %i ('%c') from %s.\n", character, character, filename );
368
+ goto fail;
369
+ }
370
+
371
+ if( face->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) {
372
+ fprintf( stderr, "WARNING: %s seems to be a bitmap font.\n", filename );
373
+ goto fail;
374
+ }
375
+
376
+ outline = &face->glyph->outline;
377
+ // fprintf(stderr,"%i importing glyph %i ('%c') of %s (advance %i, %i points)\n", glyph, character, character, filename, face->glyph->advance.x, outline->n_points );
378
+
379
+ Short *adv = new Short();
380
+ adv->setvalue( (short)(ceil(1+(face->glyph->advance.x >> 6))) );
381
+ advance->append(adv);
382
+
383
+ glyphList->setMapN(glyph, character+offset);
384
+ shape = glyphList->getShapeN(glyph);
385
+ ShapeMaker shaper( shape->getedges(), (1.0/64), -(1.0/64), 0, 0 );
386
+ shaper.setStyle( 1, -1, -1 );
387
+
388
+ FT_Outline_Decompose( outline, &decomposeFunctions, &shaper );
389
+
390
+ shaper.finish();
391
+
392
+ Rectangle *r = new Rectangle();
393
+
394
+ Rect rect = shaper.getBounds();
395
+ r->setleft( (int)rect.left );
396
+ r->settop( (int)rect.top );
397
+ r->setright( (int)rect.right );
398
+ r->setbottom( (int)rect.bottom );
399
+
400
+ r->setbits( SWFMaxBitsNeeded( true, 3, r->gettop(), r->getright(), r->getbottom() ) );
401
+ bounds->append(r);
402
+ }
403
+
404
+ if( FT_HAS_KERNING(face) ) {
405
+ FT_Vector vec;
406
+ int l, r;
407
+ for( int left=0; left<nGlyphs; left++ ) {
408
+ for( int right=0; right<nGlyphs; right++ ) {
409
+ l = FT_Get_Char_Index( face, glyphs[left] );
410
+ r = FT_Get_Char_Index( face, glyphs[right] );
411
+ if( !FT_Get_Kerning( face, l, r, FT_KERNING_DEFAULT, &vec ) ) {
412
+ if( vec.x ) {
413
+ // fprintf(stderr,"------ %i -> %i: %i\n", glyphs[left], glyphs[right], vec.x );
414
+
415
+ WideKerning *kern = new WideKerning();
416
+ kern->seta( glyphs[left] );
417
+ kern->setb( glyphs[right] );
418
+ kern->setadjustment( (short)(floor(vec.x >> 6)) );
419
+ kernings->append(kern);
420
+ }
421
+ }
422
+ }
423
+ }
424
+ }
425
+
426
+ if( glyphs ) delete glyphs;
427
+
428
+ // hacky: store the ascent in the idmap.
429
+ font_ascentmap = new char[0xff];
430
+ snprintf( font_ascentmap, 0xff, "%s_ascent", fontname );
431
+ swftctx->setMap( font_ascentmap, 1+(SCALING_FACTOR * face->ascender) / face->units_per_EM );
432
+ delete font_ascentmap;
433
+ // fprintf( stderr, "StoreAscent: %s %i\n", fontname, 1+(SCALING_FACTOR * face->ascender) / face->units_per_EM );
434
+
435
+ return;
436
+
437
+ fail:
438
+ fprintf( stderr, "WARNING: could not import %s\n", filename );
439
+ return;
440
+ }
441
+
442
+
443
+ void swft_import_ttf( xmlXPathParserContextPtr ctx, int nargs ) {
444
+ xsltTransformContextPtr tctx;
445
+ xmlChar *filename;
446
+ xsltDocumentPtr xsltdoc;
447
+ xmlDocPtr doc = NULL;
448
+ xmlNodePtr node;
449
+ xmlXPathObjectPtr obj;
450
+ Context swfctx;
451
+ char tmp[TMP_STRLEN];
452
+ xmlChar *glyphs = NULL;
453
+ int offset;
454
+ double movieVersion;
455
+
456
+ const char *fontname = NULL;
457
+
458
+ if( (nargs < 2) || (nargs > 5) ) {
459
+ xmlXPathSetArityError(ctx);
460
+ return;
461
+ }
462
+
463
+ if( nargs >= 5 ) {
464
+ offset = (int)xmlXPathPopNumber(ctx);
465
+ }
466
+ if( nargs >= 4 ) {
467
+ fontname = (const char *)xmlXPathPopString(ctx);
468
+ if( fontname[0] == 0 ) fontname = NULL;
469
+ }
470
+ if( nargs >= 3 ) {
471
+ glyphs = xmlXPathPopString(ctx);
472
+ if( glyphs[0] == 0 ) glyphs = NULL;
473
+ }
474
+
475
+ movieVersion = xmlXPathPopNumber(ctx);
476
+ filename = swft_get_filename( xmlXPathPopString(ctx) );
477
+ if( xmlXPathCheckError(ctx) )
478
+ return;
479
+
480
+ tctx = xsltXPathGetTransformContext(ctx);
481
+
482
+ bool quiet = true;
483
+ xmlXPathObjectPtr quietObj = xsltVariableLookup( tctx, (const xmlChar*)"quiet", NULL );
484
+ if( quietObj && quietObj->stringval ) { quiet = !strcmp("true",(const char*)quietObj->stringval ); };
485
+ swfctx.quiet = quiet;
486
+
487
+ doc = xmlNewDoc( (const xmlChar *)"1.0");
488
+ doc->xmlRootNode = xmlNewDocNode( doc, NULL, (const xmlChar*)"ttf", NULL );
489
+ node = doc->xmlRootNode;
490
+
491
+ //swft_addFileName( node, (const char *)filename );
492
+
493
+ swft_ctx *c = (swft_ctx*)xsltGetExtData( xsltXPathGetTransformContext(ctx), SWFT_NAMESPACE );
494
+
495
+ // create the font tag
496
+ if( movieVersion >= 8 ) {
497
+ DefineFont3 *tag = new DefineFont3();
498
+ importDefineFont3( tag, (const char *)filename, fontname, glyphs, &swfctx, c, offset );
499
+ tag->writeXML( node, &swfctx );
500
+ } else {
501
+ DefineFont2 *tag = new DefineFont2();
502
+ importDefineFont2( tag, (const char *)filename, fontname, glyphs, &swfctx, c, offset );
503
+ tag->writeXML( node, &swfctx );
504
+ }
505
+
506
+ /*
507
+ snprintf(tmp,TMP_STRLEN,"%i", 5);
508
+ xmlSetProp( node, (const xmlChar *)"format", (const xmlChar *)&tmp );
509
+ */
510
+ if( glyphs )
511
+ xmlFree( glyphs );
512
+
513
+ valuePush( ctx, xmlXPathNewNodeSet( (xmlNodePtr)doc ) );
514
+ return;
515
+
516
+ fail:
517
+ fprintf( stderr, "WARNING: could not import %s\n", filename );
518
+ return;
519
+ }