00001
00007
00008
00009 #include "NPWText.h"
00010
00011 #define kDefaultFont NPWFontNameCourier
00012 #define kDefaultFontSize 12
00013
00015 #define Chk(e) \
00016 do { \
00017 err = (e); \
00018 if (err != kNPWErrOk) \
00019 return err; \
00020 } while (0)
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #define GetUnderlinePosition(a) (a)[0]
00045 #define GetUnderlineThickness(a) (a)[1]
00046 #define GetXHeight(a) (a)[2]
00047 #define GetAscender(a) (a)[3]
00048 #define GetDescender(a) (a)[4]
00049 #define GetFirstCharCode(a) (a)[5]
00050 #define GetNumChar(a) (a)[6]
00051
00052 #define GetCharWidth(a, c) \
00053 (a)[(c) >= GetFirstCharCode(a) && (c) < GetFirstCharCode(a) + GetNumChar(a) \
00054 ? 7 + (c) - GetFirstCharCode(a) : 7]
00055
00057 static PDFInt16 afmTimesRoman[] =
00058 {
00059 -100,
00060 50,
00061 450,
00062 683,
00063 -217,
00064 32,
00065 149,
00066 250, 333, 408, 500, 500, 833, 778, 333,
00067 333, 333, 500, 564, 250, 333, 250, 278,
00068 500, 500, 500, 500, 500, 500, 500, 500,
00069 500, 500, 278, 278, 564, 564, 564, 444,
00070 921, 722, 667, 667, 722, 611, 556, 722,
00071 722, 333, 389, 722, 611, 889, 722, 722,
00072 556, 722, 667, 556, 611, 722, 722, 944,
00073 722, 722, 611, 333, 278, 333, 469, 500,
00074 333, 444, 500, 444, 500, 444, 333, 500,
00075 500, 278, 278, 500, 278, 778, 500, 500,
00076 500, 500, 333, 389, 278, 500, 500, 722,
00077 500, 500, 444, 480, 200, 480, 541, 333,
00078 500, 500, 167, 500, 500, 500, 500, 180,
00079 444, 500, 333, 333, 556, 556, 500, 500,
00080 500, 250, 453, 350, 333, 444, 444, 500,
00081 1000, 1000, 444, 333, 333, 333, 333, 333,
00082 333, 333, 333, 333, 333, 333, 333, 333,
00083 1000, 889, 276, 611, 722, 889, 310, 667,
00084 278, 278, 500, 722, 500
00085 };
00086
00088 static PDFInt16 afmTimesItalic[] =
00089 {
00090 -100,
00091 50,
00092 441,
00093 683,
00094 -217,
00095 32,
00096 149,
00097 250, 333, 420, 500, 500, 833, 778, 333,
00098 333, 333, 500, 675, 250, 333, 250, 278,
00099 500, 500, 500, 500, 500, 500, 500, 500,
00100 500, 500, 333, 333, 675, 675, 675, 500,
00101 920, 611, 611, 667, 722, 611, 611, 722,
00102 722, 333, 444, 667, 556, 833, 667, 722,
00103 611, 722, 611, 500, 556, 722, 611, 833,
00104 611, 556, 556, 389, 278, 389, 422, 500,
00105 333, 500, 500, 444, 500, 444, 278, 500,
00106 500, 278, 278, 444, 278, 722, 500, 500,
00107 500, 500, 389, 389, 278, 500, 444, 667,
00108 444, 444, 389, 400, 275, 400, 541, 389,
00109 500, 500, 167, 500, 500, 500, 500, 214,
00110 556, 500, 333, 333, 500, 500, 500, 500,
00111 500, 250, 523, 350, 333, 556, 556, 500,
00112 889, 1000, 500, 333, 333, 333, 333, 333,
00113 333, 333, 333, 333, 333, 333, 333, 333,
00114 889, 889, 276, 556, 722, 944, 310, 667,
00115 278, 278, 500, 667, 500
00116 };
00117
00119 static PDFInt16 afmTimesBold[] =
00120 {
00121 -100,
00122 50,
00123 461,
00124 683,
00125 -217,
00126 32,
00127 149,
00128 250, 333, 555, 500, 500, 1000, 833, 333,
00129 333, 333, 500, 570, 250, 333, 250, 278,
00130 500, 500, 500, 500, 500, 500, 500, 500,
00131 500, 500, 333, 333, 570, 570, 570, 500,
00132 930, 722, 667, 722, 722, 667, 611, 778,
00133 778, 389, 500, 778, 667, 944, 722, 778,
00134 611, 778, 722, 556, 667, 722, 722, 1000,
00135 722, 722, 667, 333, 278, 333, 581, 500,
00136 333, 500, 556, 444, 556, 444, 333, 500,
00137 556, 278, 333, 556, 278, 833, 556, 500,
00138 556, 556, 444, 389, 333, 556, 500, 722,
00139 500, 500, 444, 394, 220, 394, 520, 333,
00140 500, 500, 167, 500, 500, 500, 500, 278,
00141 500, 500, 333, 333, 556, 556, 500, 500,
00142 500, 250, 540, 350, 333, 500, 500, 500,
00143 1000, 1000, 500, 333, 333, 333, 333, 333,
00144 333, 333, 333, 333, 333, 333, 333, 333,
00145 1000, 1000, 300, 667, 778, 1000, 330, 722,
00146 278, 278, 500, 722, 556
00147 };
00148
00150 static PDFInt16 afmTimesBoldItalic[] =
00151 {
00152 -100,
00153 50,
00154 462,
00155 683,
00156 -217,
00157 32,
00158 149,
00159 250, 389, 555, 500, 500, 833, 778, 333,
00160 333, 333, 500, 570, 250, 333, 250, 278,
00161 500, 500, 500, 500, 500, 500, 500, 500,
00162 500, 500, 333, 333, 570, 570, 570, 500,
00163 832, 667, 667, 667, 722, 667, 667, 722,
00164 778, 389, 500, 667, 611, 889, 722, 722,
00165 611, 722, 667, 556, 611, 722, 667, 889,
00166 667, 611, 611, 333, 278, 333, 570, 500,
00167 333, 500, 500, 444, 500, 444, 333, 500,
00168 556, 278, 278, 500, 278, 778, 556, 500,
00169 500, 500, 389, 389, 278, 556, 444, 667,
00170 500, 444, 389, 348, 220, 348, 570, 389,
00171 500, 500, 167, 500, 500, 500, 500, 278,
00172 500, 500, 333, 333, 556, 556, 500, 500,
00173 500, 250, 500, 350, 333, 500, 500, 500,
00174 1000, 1000, 500, 333, 333, 333, 333, 333,
00175 333, 333, 333, 333, 333, 333, 333, 333,
00176 1000, 944, 266, 611, 722, 944, 300, 722,
00177 278, 278, 500, 722, 500
00178 };
00179
00181 static PDFInt16 afmHelvetica[] =
00182 {
00183 -100,
00184 50,
00185 523,
00186 718,
00187 -207,
00188 32,
00189 149,
00190 278, 278, 355, 556, 556, 889, 667, 222,
00191 333, 333, 389, 584, 278, 333, 278, 278,
00192 556, 556, 556, 556, 556, 556, 556, 556,
00193 556, 556, 278, 278, 584, 584, 584, 556,
00194 1015, 667, 667, 722, 722, 667, 611, 778,
00195 722, 278, 500, 667, 556, 833, 722, 778,
00196 667, 778, 722, 667, 611, 722, 667, 944,
00197 667, 667, 611, 278, 278, 278, 469, 556,
00198 222, 556, 556, 500, 556, 556, 278, 556,
00199 556, 222, 222, 500, 222, 833, 556, 556,
00200 556, 556, 333, 500, 278, 556, 500, 722,
00201 500, 500, 500, 334, 260, 334, 584, 333,
00202 556, 556, 167, 556, 556, 556, 556, 191,
00203 333, 556, 333, 333, 500, 500, 556, 556,
00204 556, 278, 537, 350, 222, 333, 333, 556,
00205 1000, 1000, 611, 333, 333, 333, 333, 333,
00206 333, 333, 333, 333, 333, 333, 333, 333,
00207 1000, 1000, 370, 556, 778, 1000, 365, 889,
00208 278, 222, 611, 944, 611
00209 };
00210
00212 static PDFInt16 afmHelveticaOblique[] =
00213 {
00214 -100,
00215 50,
00216 523,
00217 718,
00218 -207,
00219 32,
00220 149,
00221 278, 278, 355, 556, 556, 889, 667, 222,
00222 333, 333, 389, 584, 278, 333, 278, 278,
00223 556, 556, 556, 556, 556, 556, 556, 556,
00224 556, 556, 278, 278, 584, 584, 584, 556,
00225 1015, 667, 667, 722, 722, 667, 611, 778,
00226 722, 278, 500, 667, 556, 833, 722, 778,
00227 667, 778, 722, 667, 611, 722, 667, 944,
00228 667, 667, 611, 278, 278, 278, 469, 556,
00229 222, 556, 556, 500, 556, 556, 278, 556,
00230 556, 222, 222, 500, 222, 833, 556, 556,
00231 556, 556, 333, 500, 278, 556, 500, 722,
00232 500, 500, 500, 334, 260, 334, 584, 333,
00233 556, 556, 167, 556, 556, 556, 556, 191,
00234 333, 556, 333, 333, 500, 500, 556, 556,
00235 556, 278, 537, 350, 222, 333, 333, 556,
00236 1000, 1000, 611, 333, 333, 333, 333, 333,
00237 333, 333, 333, 333, 333, 333, 333, 333,
00238 1000, 1000, 370, 556, 778, 1000, 365, 889,
00239 278, 222, 611, 944, 611
00240 };
00241
00243 static PDFInt16 afmHelveticaBold[] =
00244 {
00245 -100,
00246 50,
00247 532,
00248 718,
00249 -207,
00250 32,
00251 149,
00252 278, 333, 474, 556, 556, 889, 722, 278,
00253 333, 333, 389, 584, 278, 333, 278, 278,
00254 556, 556, 556, 556, 556, 556, 556, 556,
00255 556, 556, 333, 333, 584, 584, 584, 611,
00256 975, 722, 722, 722, 722, 667, 611, 778,
00257 722, 278, 556, 722, 611, 833, 722, 778,
00258 667, 778, 722, 667, 611, 722, 667, 944,
00259 667, 667, 611, 333, 278, 333, 584, 556,
00260 278, 556, 611, 556, 611, 556, 333, 611,
00261 611, 278, 278, 556, 278, 889, 611, 611,
00262 611, 611, 389, 556, 333, 611, 556, 778,
00263 556, 556, 500, 389, 280, 389, 584, 333,
00264 556, 556, 167, 556, 556, 556, 556, 238,
00265 500, 556, 333, 333, 611, 611, 556, 556,
00266 556, 278, 556, 350, 278, 500, 500, 556,
00267 1000, 1000, 611, 333, 333, 333, 333, 333,
00268 333, 333, 333, 333, 333, 333, 333, 333,
00269 1000, 1000, 370, 611, 778, 1000, 365, 889,
00270 278, 278, 611, 944, 611
00271 };
00272
00274 static PDFInt16 afmHelveticaBoldOblique[] =
00275 {
00276 -100,
00277 50,
00278 532,
00279 718,
00280 -207,
00281 32,
00282 149,
00283 278, 333, 474, 556, 556, 889, 722, 278,
00284 333, 333, 389, 584, 278, 333, 278, 278,
00285 556, 556, 556, 556, 556, 556, 556, 556,
00286 556, 556, 333, 333, 584, 584, 584, 611,
00287 975, 722, 722, 722, 722, 667, 611, 778,
00288 722, 278, 556, 722, 611, 833, 722, 778,
00289 667, 778, 722, 667, 611, 722, 667, 944,
00290 667, 667, 611, 333, 278, 333, 584, 556,
00291 278, 556, 611, 556, 611, 556, 333, 611,
00292 611, 278, 278, 556, 278, 889, 611, 611,
00293 611, 611, 389, 556, 333, 611, 556, 778,
00294 556, 556, 500, 389, 280, 389, 584, 333,
00295 556, 556, 167, 556, 556, 556, 556, 238,
00296 500, 556, 333, 333, 611, 611, 556, 556,
00297 556, 278, 556, 350, 278, 500, 500, 556,
00298 1000, 1000, 611, 333, 333, 333, 333, 333,
00299 333, 333, 333, 333, 333, 333, 333, 333,
00300 1000, 1000, 370, 611, 778, 1000, 365, 889,
00301 278, 278, 611, 944, 611,
00302 };
00303
00305 static PDFInt16 afmCourier[] =
00306 {
00307 -100,
00308 50,
00309 439,
00310 629,
00311 -157,
00312 32,
00313 1,
00314 600
00315 };
00316
00318 static PDFInt16 afmSymbol[] =
00319 {
00320 -100,
00321 50,
00322 500,
00323 0,
00324 0,
00325 32,
00326 189,
00327 250, 333, 713, 500, 549, 833, 778, 439,
00328 333, 333, 500, 549, 250, 549, 250, 278,
00329 500, 500, 500, 500, 500, 500, 500, 500,
00330 500, 500, 278, 278, 549, 549, 549, 444,
00331 549, 722, 667, 722, 612, 611, 763, 603,
00332 722, 333, 631, 722, 686, 889, 722, 722,
00333 768, 741, 556, 592, 611, 690, 439, 768,
00334 645, 795, 611, 333, 863, 333, 658, 500,
00335 500, 631, 549, 549, 494, 439, 521, 411,
00336 603, 329, 603, 549, 549, 576, 521, 549,
00337 549, 521, 549, 603, 439, 576, 713, 686,
00338 493, 686, 494, 480, 200, 480, 549, 750,
00339 620, 247, 549, 167, 713, 500, 753, 753,
00340 753, 753, 1042, 987, 603, 987, 603, 400,
00341 549, 411, 549, 549, 713, 494, 460, 549,
00342 549, 549, 549, 1000, 603, 1000, 658, 823,
00343 686, 795, 987, 768, 768, 823, 768, 768,
00344 713, 713, 713, 713, 713, 713, 713, 768,
00345 713, 790, 790, 890, 823, 549, 250, 713,
00346 603, 603, 1042, 987, 603, 987, 603, 494,
00347 329, 790, 790, 786, 713, 384, 384, 384,
00348 384, 384, 384, 494, 494, 494, 494, 329,
00349 274, 686, 686, 686, 384, 384, 384, 384,
00350 384, 384, 494, 494, 494
00351 };
00352
00354 static PDFInt16 afmZapfDingbats[] =
00355 {
00356 -100,
00357 50,
00358 700,
00359 0,
00360 0,
00361 32,
00362 202,
00363 278, 974, 961, 974, 980, 719, 789, 790,
00364 791, 690, 960, 939, 549, 855, 911, 933,
00365 911, 945, 974, 755, 846, 762, 761, 571,
00366 677, 763, 760, 759, 754, 494, 552, 537,
00367 577, 692, 786, 788, 788, 790, 793, 794,
00368 816, 823, 789, 841, 823, 833, 816, 831,
00369 923, 744, 723, 749, 790, 792, 695, 776,
00370 768, 792, 759, 707, 708, 682, 701, 826,
00371 815, 789, 789, 707, 687, 696, 689, 786,
00372 787, 713, 791, 785, 791, 873, 761, 762,
00373 762, 759, 759, 892, 892, 788, 784, 438,
00374 138, 277, 415, 392, 392, 668, 668, 390,
00375 390, 317, 317, 276, 276, 509, 509, 410,
00376 410, 234, 234, 334, 334, 732, 544, 544,
00377 910, 667, 760, 760, 776, 595, 694, 626,
00378 788, 788, 788, 788, 788, 788, 788, 788,
00379 788, 788, 788, 788, 788, 788, 788, 788,
00380 788, 788, 788, 788, 788, 788, 788, 788,
00381 788, 788, 788, 788, 788, 788, 788, 788,
00382 788, 788, 788, 788, 788, 788, 788, 788,
00383 894, 838, 1016, 458, 748, 924, 748, 918,
00384 927, 928, 928, 834, 873, 828, 924, 924,
00385 917, 930, 931, 463, 883, 836, 836, 867,
00386 867, 696, 696, 874, 874, 760, 946, 771,
00387 865, 771, 888, 967, 888, 831, 873, 927,
00388 970, 918
00389 };
00390
00392 typedef struct
00393 {
00394 NPWConstText name;
00395 PDFInt16 const *afm;
00396 } FontMetrics;
00397
00399 FontMetrics const fonts[] =
00400 {
00401 {NPWFontNameTimesRoman, afmTimesRoman},
00402 {NPWFontNameTimesItalic, afmTimesItalic},
00403 {NPWFontNameTimesBold, afmTimesBold},
00404 {NPWFontNameTimesBoldItalic, afmTimesBoldItalic},
00405 {NPWFontNameHelvetica, afmHelvetica},
00406 {NPWFontNameHelveticaOblique, afmHelveticaOblique},
00407 {NPWFontNameHelveticaBold, afmHelveticaBold},
00408 {NPWFontNameHelveticaBoldOblique, afmHelveticaBoldOblique},
00409 {NPWFontNameCourier, afmCourier},
00410 {NPWFontNameCourierOblique, afmCourier},
00411 {NPWFontNameCourierBold, afmCourier},
00412 {NPWFontNameCourierBoldOblique, afmCourier},
00413 {NPWFontNameSymbol, afmSymbol},
00414 {NPWFontNameZapfDingbats, afmZapfDingbats},
00415 {NULL, NULL}
00416 };
00417
00423 static NPWBoolean AreStrEq(NPWConstText s1, NPWConstText s2)
00424 {
00425 for ( ; s1[0] && s1[0] == s2[0]; s1++, s2++)
00426 ;
00427 return s1[0] == s2[0];
00428 }
00429
00430 NPWErr NPWTextFont(NPWFont *font, NPWConstText name, NPWFloat size)
00431 {
00432 NPWInt i;
00433
00434 for (i = 0; fonts[i].name && !AreStrEq(name, fonts[i].name); i++)
00435 ;
00436 if (!fonts[i].name)
00437 return kNPWUnknownFont;
00438
00439 font->size = size;
00440 font->metrics = (void const *)fonts[i].afm;
00441 return kNPWErrOk;
00442 }
00443
00444 void NPWTextSize(NPWFont const *font,
00445 NPWConstText str, NPWInt len,
00446 NPWFloat *width, NPWFloat *height)
00447 {
00448 if (width)
00449 {
00450 NPWInt i, w;
00451
00452 for (i = w = 0; len < 0 ? str[i] : i < len; i++)
00453 w += GetCharWidth((PDFInt16 const *)font->metrics, str[i]);
00454 *width = w * font->size / 1000L;
00455 }
00456
00457 if (height)
00458 *height = font->size;
00459 }
00460
00461 NPWConstText NPWFindFont(NPWCharStyle const *charStyle, NPWFont *font)
00462 {
00463 NPWConstText refName = NULL;
00464
00465 if (AreStrEq(charStyle->fontBaseName, "Times"))
00466 refName = charStyle->isBold ? charStyle->isItalic ? NPWFontNameTimesBoldItalic
00467 : NPWFontNameTimesBold
00468 : charStyle->isItalic ? NPWFontNameTimesItalic
00469 : NPWFontNameTimesRoman;
00470 else if (AreStrEq(charStyle->fontBaseName, "Helvetica"))
00471 refName = charStyle->isBold ? charStyle->isItalic ? NPWFontNameHelveticaBoldOblique
00472 : NPWFontNameHelveticaBold
00473 : charStyle->isItalic ? NPWFontNameHelveticaOblique
00474 : NPWFontNameHelvetica;
00475 else if (AreStrEq(charStyle->fontBaseName, "Courier"))
00476 refName = charStyle->isBold ? charStyle->isItalic ? NPWFontNameCourierBoldOblique
00477 : NPWFontNameCourierBold
00478 : charStyle->isItalic ? NPWFontNameCourierOblique
00479 : NPWFontNameCourier;
00480 else if (AreStrEq(charStyle->fontBaseName, "Symbol"))
00481 refName = NPWFontNameSymbol;
00482 else if (AreStrEq(charStyle->fontBaseName, "ZapfDingbats"))
00483 refName = NPWFontNameZapfDingbats;
00484
00485
00486 if (!refName)
00487 refName = NPWFontNameCourier;
00488
00489 if (font)
00490 NPWTextFont(font, refName, charStyle->size);
00491
00492 return refName;
00493 }
00494
00495 void NPWFontMetrics(NPWFont const *font,
00496 NPWFloat *ascender,
00497 NPWFloat *descender,
00498 NPWFloat *xHeight)
00499 {
00500 if (ascender)
00501 *ascender = GetAscender((PDFInt16 const *)font->metrics);
00502 if (descender)
00503 *descender = GetDescender((PDFInt16 const *)font->metrics);
00504 if (xHeight)
00505 *xHeight = GetXHeight((PDFInt16 const *)font->metrics);
00506 }
00507
00508 NPWBoolean NPWBreakNextLine(NPWConstText str, NPWInt len, NPWInt start,
00509 NPWFloat lineMaxWidth,
00510 NPWMarkupCBEntry const markupCBTable[],
00511 NPWInt *lineBr, NPWFloat *lineWidth, NPWInt *nSpaces,
00512 NPWBoolean *suspended,
00513 NPWCharStyle *style,
00514 NPWParFormat *parFormat)
00515 {
00516 NPWInt cIx;
00517 NPWInt spIx;
00518 NPWFloat w;
00519 NPWInt nSp;
00520 NPWFloat w0;
00521 NPWFloat wch;
00522 NPWFont font;
00523
00524
00525 if (len < 0)
00526 for (len = 0; str[len]; len++)
00527 ;
00528
00529 if (len <= start)
00530 return FALSE;
00531
00532 (void)NPWFindFont(style, &font);
00533
00534 for (cIx = start, w = 0, spIx = -1, w0 = w, nSp = 0;
00535 cIx < len && str[cIx] != '\n';
00536 )
00537 {
00538
00539 if (markupCBTable)
00540 {
00541 NPWInt i, count;
00542 NPWMarkupActionFlag action;
00543
00544 for (i = count = 0; markupCBTable[i].f; i++)
00545 {
00546 action = markupCBTable[i].f(markupCBTable[i].userData,
00547 str + cIx, len - cIx,
00548 &count, style, parFormat);
00549 cIx += count;
00550 if (!(action & kNPWMarkupActionFlagNotRecognized))
00551 {
00552 if (action & kNPWMarkupActionFlagNewStyle)
00553 (void)NPWFindFont(style, &font);
00554 if (action & kNPWMarkupActionFlagSuspend)
00555 {
00556 if (suspended)
00557 *suspended = TRUE;
00558 goto endOfPar;
00559 }
00560 if (action & kNPWMarkupActionFlagEndOfPar)
00561 goto endOfPar;
00562
00563 goto contMainLoop;
00564 }
00565 }
00566 }
00567
00568 if (str[cIx] == ' ')
00569 {
00570 spIx = cIx;
00571 w0 = w;
00572 nSp++;
00573 }
00574 NPWTextSize(&font, &str[cIx], 1, &wch, NULL);
00575 w += wch;
00576 if (w > lineMaxWidth
00577 && w > wch
00578 && lineMaxWidth >= 0)
00579 {
00580 *lineWidth = spIx >= 0 ? w0 : w - wch;
00581 *nSpaces = spIx >= 0 ? nSp - 1 : nSp;
00582 w = spIx >= 0 ? w - w0 : wch;
00583 if (spIx >= 0)
00584 {
00585 NPWTextSize(&font, " ", 1, &wch, NULL);
00586 w -= wch;
00587 }
00588 nSp = str[cIx] == ' ' ? 1 : 0;
00589 *lineBr = spIx >= 0 ? spIx + 1 : cIx;
00590 return TRUE;
00591 }
00592
00593 cIx++;
00594 contMainLoop:
00595 ;
00596 }
00597
00598 endOfPar:
00599 *lineWidth = w;
00600 *nSpaces = nSp;
00601 *lineBr = cIx;
00602
00603 return TRUE;
00604 }
00605
00606 void NPWTextLayoutInit(NPWTextLayoutState *state,
00607 NPWMarkupCBEntry const markupCBTable[])
00608 {
00609 state->markupCBTable = markupCBTable;
00610
00611 state->style.fontBaseName = "Times";
00612 state->style.size = 12;
00613 state->style.isBold = FALSE;
00614 state->style.isItalic = FALSE;
00615 state->style.isUnderlined = FALSE;
00616 state->style.isHidden = FALSE;
00617 state->style.verticalAlignment = kNPWCharVertAlignmentNormal;
00618 state->style.color.r = 0;
00619 state->style.color.g = 0;
00620 state->style.color.b = 0;
00621
00622 state->parFormat.alignment = kNPWAlignmentJustify;
00623 state->parFormat.indent0 = 24;
00624 state->parFormat.indent = 0;
00625 state->parFormat.lineSpacing = 1200;
00626 state->parFormat.parSpacing = 400;
00627
00628 state->x = 100;
00629 state->y = 800;
00630 state->bottom = 0;
00631 }
00632
00633 void NPWLayoutSetDefaultCharStyle(NPWTextLayoutState *state,
00634 NPWCharStyle const *style)
00635 {
00636 state->style = *style;
00637 }
00638
00639 void NPWLayoutSetDefaultParagraphStyle(NPWTextLayoutState *state,
00640 NPWParFormat const *parFormat)
00641 {
00642 state->parFormat = *parFormat;
00643 }
00644
00645 void NPWTextLayoutSetPosition(NPWTextLayoutState *state,
00646 NPWFloat x, NPWFloat y)
00647 {
00648 state->x = x;
00649 state->y = y;
00650 }
00651
00652 void NPWTextLayoutSetLineWidths(NPWTextLayoutState *state,
00653 NPWFloat const lineMaxWidths[], NPWInt lineMWLen)
00654 {
00655 state->lineMaxWidths = lineMaxWidths;
00656 state->lineMWLen = lineMWLen;
00657 }
00658
00659 void NPWTextLayoutSetBottom(NPWTextLayoutState *state,
00660 NPWFloat bottom)
00661 {
00662 state->bottom = bottom;
00663 }
00664
00665 void NPWTextLayoutSetText(NPWTextLayoutState *state,
00666 NPWConstText str, NPWInt len)
00667 {
00668 state->str = str;
00669 if (len < 0)
00670 for (len = 0; str[len]; len++)
00671 ;
00672 state->len = len;
00673 state->i = 0;
00674 state->newParagraph = TRUE;
00675 }
00676
00677 NPWErr NPWTextLayoutWrite(NPW *pdf,
00678 NPWTextLayoutState *state)
00679 {
00680 NPWInt lineBr;
00681 NPWFloat lineWidth;
00682 NPWInt nSpaces;
00683 NPWFloat xlast = 0, xnew = 0;
00684 NPWInt spanB, spanE;
00685 NPWInt spanBNext;
00686 NPWInt currentCharAlignment = kNPWCharVertAlignmentNormal;
00687 NPWFloat vskip;
00688 NPWFloat currentIndent;
00689 NPWRGBColor color = {0, 0, 0};
00690 NPWCharStyle styleTmp;
00691 NPWParFormat parFormatTmp;
00692 NPWFloat lineMaxWidth;
00693 NPWBoolean suspended = FALSE;
00694 NPWBoolean firstMove = TRUE;
00695 NPWErr err;
00696
00697
00698 Chk(NPWGraphicsBeginText(pdf));
00699
00700
00701 nextParagraph:
00702 if (state->markupCBTable)
00703 {
00704 NPWInt j, count;
00705 NPWMarkupActionFlag action;
00706
00707 while (state->i < state->len)
00708 {
00709 for (j = count = 0; state->markupCBTable[j].f; j++)
00710 {
00711 action = state->markupCBTable[j].f(state->markupCBTable[j].userData,
00712 state->str + state->i, state->len - state->i,
00713 &count, &state->style, &state->parFormat);
00714 state->i += count;
00715 if (action & kNPWMarkupActionFlagSuspend)
00716 {
00717 Chk(NPWGraphicsEndText(pdf));
00718 return kNPWErrSuspended;
00719 }
00720 if (!(action & kNPWMarkupActionFlagNotRecognized))
00721 goto contNextMarkup;
00722 }
00723 break;
00724 contNextMarkup:
00725 ;
00726 }
00727 }
00728
00729
00730 Chk(NPWGraphicsSetTextFont(pdf, NPWFindFont(&state->style, NULL), state->style.size));
00731 Chk(NPWGraphicsSetTextLeading(pdf, state->style.size * state->parFormat.lineSpacing / 1000));
00732
00733 xnew = state->x;
00734 if (firstMove)
00735 {
00736 Chk(NPWGraphicsMoveText(pdf, state->x, state->y));
00737 xlast = 0;
00738 firstMove = FALSE;
00739 }
00740 else
00741 {
00742 Chk(NPWGraphicsMoveText(pdf, state->x - xlast, firstMove ? state->y : 0));
00743 xlast = state->x;
00744 }
00745
00746 while (state->i < state->len && state->str[state->i] != '\n' && !suspended)
00747 {
00748
00749 vskip = state->newParagraph
00750 ? -state->style.size * (state->parFormat.lineSpacing + state->parFormat.parSpacing) / 1000
00751 : state->i > 0 ? -state->style.size * state->parFormat.lineSpacing / 1000 : 0;
00752 if (state->y < state->bottom)
00753 break;
00754
00755
00756 if (state->newParagraph)
00757 currentIndent = state->parFormat.indent + state->parFormat.indent0;
00758 else
00759 currentIndent = state->parFormat.indent;
00760
00761
00762 styleTmp = state->style;
00763 parFormatTmp = state->parFormat;
00764 lineMaxWidth
00765 = state->lineMWLen > 0
00766 ? state->lineMaxWidths[state->i < state->lineMWLen ? state->i : state->lineMWLen - 1]
00767 - currentIndent
00768 : -1;
00769 if (!NPWBreakNextLine(state->str, state->len, state->i,
00770 lineMaxWidth,
00771 state->markupCBTable,
00772 &lineBr, &lineWidth, &nSpaces, &suspended,
00773 &styleTmp, &parFormatTmp))
00774 break;
00775
00776
00777 switch (state->parFormat.alignment)
00778 {
00779 case kNPWAlignmentCenter:
00780 xnew = (lineMaxWidth - lineWidth) / 2 + currentIndent;
00781 Chk(NPWGraphicsMoveText(pdf,
00782 xnew - xlast,
00783 vskip));
00784 xlast = xnew;
00785 break;
00786 case kNPWAlignmentRight:
00787 xnew = lineMaxWidth - lineWidth + currentIndent;
00788 Chk(NPWGraphicsMoveText(pdf,
00789 xnew - xlast,
00790 vskip));
00791 xlast = xnew;
00792 break;
00793 default:
00794 xnew = currentIndent;
00795 Chk(NPWGraphicsMoveText(pdf,
00796 xnew - xlast,
00797 vskip));
00798 xlast = xnew;
00799 Chk(NPWGraphicsSetWordSpace(pdf,
00800 lineBr < state->len && state->str[lineBr] != '\n'
00801 && state->parFormat.alignment == kNPWAlignmentJustify
00802 && !suspended
00803 ? (lineMaxWidth - lineWidth) / nSpaces : 0));
00804 break;
00805 }
00806 state->newParagraph = FALSE;
00807 state->y += vskip;
00808
00809
00810 styleTmp = state->style;
00811 parFormatTmp = state->parFormat;
00812 for (spanB = state->i; spanB < lineBr; spanB = spanBNext)
00813 {
00814 for (spanE = spanBNext = spanB; spanE < lineBr; spanE++)
00815 if (state->markupCBTable)
00816 {
00817 NPWInt i, count;
00818 NPWMarkupActionFlag action;
00819
00820 for (i = count = 0; state->markupCBTable[i].f; i++)
00821 {
00822 action = state->markupCBTable[i].f(state->markupCBTable[i].userData,
00823 state->str + spanE, lineBr - spanE,
00824 &count, &styleTmp, &parFormatTmp);
00825 spanBNext = spanE + count;
00826 if (!(action & kNPWMarkupActionFlagNotRecognized))
00827 goto spanDone;
00828 }
00829 }
00830 if (spanBNext < spanE)
00831 spanBNext = spanE;
00832 spanDone:
00833 if (spanE > spanB)
00834 {
00835 Chk(NPWGraphicsSetTextFont(pdf, NPWFindFont(&state->style, NULL), state->style.size));
00836 if (state->style.color.r != color.r || state->style.color.g != color.g
00837 || state->style.color.b != color.b)
00838 {
00839 color = state->style.color;
00840 if (color.r == color.g && color.r == color.b)
00841 Chk(NPWGraphicsGray(pdf, (NPWFloat)color.r / 255));
00842 else
00843 Chk(NPWGraphicsRGB(pdf,
00844 (NPWFloat)color.r / 255, (NPWFloat)color.g / 255, (NPWFloat)color.b / 255));
00845 }
00846
00847 if (state->style.verticalAlignment != currentCharAlignment)
00848 {
00849 switch (state->style.verticalAlignment)
00850 {
00851 case kNPWCharVertAlignmentNormal:
00852 Chk(NPWGraphicsSetTextRise(pdf, 0));
00853 break;
00854 case kNPWCharVertAlignmentSubscript:
00855 Chk(NPWGraphicsSetTextRise(pdf, -styleTmp.size * 3 / 10));
00856 break;
00857 case kNPWCharVertAlignmentSuperscript:
00858 Chk(NPWGraphicsSetTextRise(pdf, styleTmp.size * 3 / 10));
00859 break;
00860 }
00861 currentCharAlignment = state->style.verticalAlignment;
00862 }
00863 if (!state->style.isHidden)
00864 Chk(NPWGraphicsShowText(pdf, state->str + spanB, spanE - spanB));
00865 else
00866 {
00867 NPWFloat w;
00868 NPWFont font;
00869
00870 (void)NPWFindFont(&state->style, &font);
00871 NPWTextSize(&font, state->str + spanB, spanE - spanB, &w, NULL);
00872 Chk(NPWGraphicsHorSkip(pdf, 1000 * w / font.size));
00873 }
00874 if (state->style.isUnderlined)
00875 {
00876
00877 }
00878 }
00879
00880 state->style = styleTmp;
00881 state->parFormat = parFormatTmp;
00882 }
00883
00884 state->i = lineBr;
00885 }
00886
00887
00888 if (!suspended && state->i < state->len && state->str[state->i] == '\n')
00889 {
00890 state->i++;
00891 state->newParagraph = TRUE;
00892 goto nextParagraph;
00893 }
00894
00895
00896 Chk(NPWGraphicsEndText(pdf));
00897
00898 return suspended ? kNPWErrSuspended : state->i < state->len ? kNPWErrIncomplete : kNPWErrOk;
00899 }
00900
00901 NPWErr NPWTextLayoutVerticalSkip(NPWTextLayoutState *state,
00902 NPWFloat v, NPWFloat *ylow)
00903 {
00904 if (state->y - v < state->bottom)
00905 return kNPWErrIncomplete;
00906 state->y -= v;
00907 if (ylow)
00908 *ylow = state->y;
00909 return kNPWErrOk;
00910 }
00911
00912 NPWErr NPWTextWrite(NPW *pdf,
00913 NPWConstText str, NPWInt len,
00914 NPWFloat x, NPWFloat y,
00915 NPWCharStyle const *style, NPWAlignment alignment)
00916 {
00917 NPWTextLayoutState state;
00918
00919 NPWTextLayoutInit(&state, NULL);
00920 NPWTextLayoutSetPosition(&state, x, y);
00921 NPWTextLayoutSetLineWidths(&state, NULL, 0);
00922 if (style)
00923 state.style = *style;
00924 state.parFormat.alignment = alignment;
00925 state.parFormat.indent0 = state.parFormat.indent = 0;
00926 state.parFormat.lineSpacing = state.parFormat.parSpacing = 0;
00927 NPWTextLayoutSetText(&state, str, len);
00928 return NPWTextLayoutWrite(pdf, &state);
00929 }