1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/miniline.c,v 1.40 2011/09/07 04:28:51 cvsps Exp $
19 */
20
21 #define _INCLUDE_FROM_MINILINE_C_
22
23 #include "tgifdefs.h"
24
25 #include "auxtext.e"
26 #include "choice.e"
27 #include "color.e"
28 #include "cutpaste.e"
29 #include "dialog.e"
30 #include "drawing.e"
31 #include "dup.e"
32 #include "file.e"
33 #include "font.e"
34 #include "inmethod.e"
35 #include "miniline.e"
36 #include "move.e"
37 #include "msg.e"
38 #include "obj.e"
39 #include "pattern.e"
40 #include "ps.e"
41 #include "raster.e"
42 #include "rect.e"
43 #include "setup.e"
44 #include "strtbl.e"
45 #include "text.e"
46 #include "util.e"
47 #include "wb.e"
48
49 #define USE_SEG 0
50 #define USE_SUP 1
51 #define USE_SUB 2
52
53 TextHighlightInfo gstTextHighlightInfo;
54
55 CopyUTF8Info gstCopyUTF8Info;
56
57 /*
58 * textOrigX, textOrigY, textCurX, textCurY, textCurBaselineY are
59 * UNSCALED screen offsets
60 * textAbsX, and textAbsY are absolute coordinates
61 */
62 int textOrigX=20, textOrigY=20, textOrigBaselineY=20;
63 int textAbsX=INVALID, textAbsY=INVALID, textAbsBaselineY=INVALID;
64
65 int textCurX=20, textCurY=20, textCurBaselineY=0;
66 int textCurIndex=0;
67 int textEndX=20, textEndY=20, textEndBaselineY=0;
68 int textEndIndex=0;
69 /*
70 * The following is updated to grown in UpdateEditTextArea().
71 */
72 int textAbsMinLBearing=0, textAbsMaxRExtra=0;
73 int textW=0, textH=0; /* absolute for the current text font */
74
75 int textHighlight=FALSE;
76
77 struct ObjRec *curTextObj=NULL;
78
79 struct BBRec curTextOBBox, curTextBBox;
80
81 StrBlockInfo *curStrBlock=NULL; /* block must always be SB_SIMPLE */
82 StrBlockInfo *endStrBlock=NULL; /* block must always be SB_SIMPLE */
83 MiniLineInfo *firstMiniLine=NULL, *lastMiniLine=NULL;
84
85 int escPressed=FALSE;
86
87 int dontRecalcStrSegMetrics=FALSE;
88
89 int curTextOutlineW=7, curTextOutlineHalfW=3;
90
91 int drawWinHasFocus=FALSE;
92
93 /* --------------------- ClearCopyUTF8Info() --------------------- */
94
ClearCopyUTF8Info()95 void ClearCopyUTF8Info()
96 {
97 memset(&gstCopyUTF8Info, 0, sizeof(CopyUTF8Info));
98 }
99
100 static
DebugCopyUTF8Info()101 void DebugCopyUTF8Info()
102 {
103 #ifdef NOT_DEFINED
104 if (gstCopyUTF8Info.single_byte_valid) {
105 fprintf(stderr, "Single byte:\n");
106 fprintf(stderr, "\tFont: %s\n",
107 fontMenuStr[gstCopyUTF8Info.single_byte_seg.font]);
108 fprintf(stderr, "\tStyle: %1d\n",
109 gstCopyUTF8Info.single_byte_seg.style);
110 fprintf(stderr, "\tSize: %1d\n",
111 SzUnitToFontSize(gstCopyUTF8Info.single_byte_seg.sz_unit));
112 }
113 if (gstCopyUTF8Info.double_byte_valid) {
114 fprintf(stderr, "Double byte:\n");
115 fprintf(stderr, "\tFont: %s\n",
116 fontMenuStr[gstCopyUTF8Info.double_byte_seg.font]);
117 fprintf(stderr, "\tStyle: %1d\n",
118 gstCopyUTF8Info.double_byte_seg.style);
119 fprintf(stderr, "\tSize: %1d\n",
120 SzUnitToFontSize(gstCopyUTF8Info.double_byte_seg.sz_unit));
121 }
122 #endif /* NOT_DEFINED */
123 }
124
SetCopyUTF8FontInfo(pStrSeg,double_byte)125 void SetCopyUTF8FontInfo(pStrSeg, double_byte)
126 StrSegInfo *pStrSeg;
127 int double_byte;
128 {
129 if (double_byte) {
130 memcpy(&gstCopyUTF8Info.double_byte_seg, pStrSeg, sizeof(StrSegInfo));
131 gstCopyUTF8Info.double_byte_seg.font_name = NULL;
132 gstCopyUTF8Info.double_byte_seg.dyn_str.sz = 0;
133 gstCopyUTF8Info.double_byte_seg.dyn_str.s = NULL;
134 gstCopyUTF8Info.double_byte_seg.owner = NULL;
135
136 gstCopyUTF8Info.double_byte_valid = TRUE;
137 } else {
138 memcpy(&gstCopyUTF8Info.single_byte_seg, pStrSeg, sizeof(StrSegInfo));
139 gstCopyUTF8Info.single_byte_seg.font_name = NULL;
140 gstCopyUTF8Info.single_byte_seg.dyn_str.sz = 0;
141 gstCopyUTF8Info.single_byte_seg.dyn_str.s = NULL;
142 gstCopyUTF8Info.single_byte_seg.owner = NULL;
143
144 gstCopyUTF8Info.single_byte_valid = TRUE;
145 }
146 }
147
CalcSingleByteInfoForCopyUTF8(pn_font_index)148 int CalcSingleByteInfoForCopyUTF8(pn_font_index)
149 int *pn_font_index;
150 {
151 StrBlockInfo *pStrBlock=NULL;
152
153 if (curStrBlock != endStrBlock || curStrBlock->type != SB_SIMPLE ||
154 !curStrBlock->seg->double_byte) {
155 return FALSE;
156 }
157 for (pStrBlock=curStrBlock->prev; pStrBlock != NULL;
158 pStrBlock=pStrBlock->prev) {
159 if (pStrBlock->type == SB_SIMPLE && !pStrBlock->seg->double_byte) {
160 SetCopyUTF8FontInfo(pStrBlock->seg, FALSE);
161 DebugCopyUTF8Info();
162 return TRUE;
163 }
164 }
165 return FALSE;
166 }
167
168 static
FoundSingleByteFontAtStrBlock(pStrBlock,pStrSeg,double_byte)169 int FoundSingleByteFontAtStrBlock(pStrBlock, pStrSeg, double_byte)
170 StrBlockInfo *pStrBlock;
171 StrSegInfo *pStrSeg;
172 int double_byte;
173 {
174 if (pStrBlock->type == SB_SIMPLE &&
175 pStrBlock->seg->double_byte == double_byte) {
176 SetCopyUTF8FontInfo(pStrBlock->seg, FALSE);
177 DebugCopyUTF8Info();
178
179 if (pStrSeg != NULL) {
180 memcpy(pStrSeg, pStrBlock->seg, sizeof(StrSegInfo));
181 pStrSeg->font_name = NULL;
182 pStrSeg->dyn_str.sz = 0;
183 pStrSeg->dyn_str.s = NULL;
184 pStrSeg->owner = NULL;
185 }
186 return TRUE;
187 }
188 return FALSE;
189 }
190
191 static
CanFindSingleOrDoubleByteFontAtCursor(pStrSeg,double_byte)192 int CanFindSingleOrDoubleByteFontAtCursor(pStrSeg, double_byte)
193 StrSegInfo *pStrSeg;
194 int double_byte;
195 {
196 StrBlockInfo *pStrBlock=NULL;
197 MiniLineInfo *pMiniLine=NULL;
198
199 if (curStrBlock->type != SB_SIMPLE) {
200 return FALSE;
201 }
202 if (curStrBlock->seg->double_byte == double_byte) {
203 return TRUE;
204 }
205 for (pStrBlock=curStrBlock->prev; pStrBlock != NULL;
206 pStrBlock=pStrBlock->prev) {
207 if (FoundSingleByteFontAtStrBlock(pStrBlock, pStrSeg, double_byte)) {
208 return TRUE;
209 }
210 }
211 for (pMiniLine=curStrBlock->owner_mini_line->prev; pMiniLine != NULL;
212 pMiniLine=pMiniLine->prev) {
213 for (pStrBlock=pMiniLine->last_block; pStrBlock != NULL;
214 pStrBlock=pStrBlock->prev) {
215 if (FoundSingleByteFontAtStrBlock(pStrBlock, pStrSeg, double_byte)) {
216 return TRUE;
217 }
218 }
219 }
220 for (pStrBlock=curStrBlock->next; pStrBlock != NULL;
221 pStrBlock=pStrBlock->next) {
222 if (FoundSingleByteFontAtStrBlock(pStrBlock, pStrSeg, double_byte)) {
223 return TRUE;
224 }
225 }
226 for (pMiniLine=curStrBlock->owner_mini_line->next; pMiniLine != NULL;
227 pMiniLine=pMiniLine->next) {
228 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
229 pStrBlock=pStrBlock->next) {
230 if (FoundSingleByteFontAtStrBlock(pStrBlock, pStrSeg, double_byte)) {
231 return TRUE;
232 }
233 }
234 }
235 return FALSE;
236 }
237
CanFindSingleByteFontAtCursor(pStrSeg)238 int CanFindSingleByteFontAtCursor(pStrSeg)
239 StrSegInfo *pStrSeg;
240 {
241 return CanFindSingleOrDoubleByteFontAtCursor(pStrSeg, FALSE);
242 }
243
CanFindDoubleByteFontAtCursor(pStrSeg)244 int CanFindDoubleByteFontAtCursor(pStrSeg)
245 StrSegInfo *pStrSeg;
246 {
247 return CanFindSingleOrDoubleByteFontAtCursor(pStrSeg, TRUE);
248 }
249
250 /* --------------------- DrawTextInfo Functions --------------------- */
251
252 static DrawTextInfo gstDrawTextInfo;
253 static int gnDrawTextInfoValid=FALSE;
254
SaveDrawTextInfo(pDrawTextInfo)255 void SaveDrawTextInfo(pDrawTextInfo)
256 DrawTextInfo *pDrawTextInfo;
257 {
258 memset(pDrawTextInfo, 0, sizeof(DrawTextInfo));
259
260 memcpy(&pDrawTextInfo->text_highlight_info, &gstTextHighlightInfo,
261 sizeof(TextHighlightInfo));
262
263 pDrawTextInfo->text_orig_x = textOrigX;
264 pDrawTextInfo->text_orig_y = textOrigY;
265 pDrawTextInfo->text_orig_baseline_y = textOrigBaselineY;
266 pDrawTextInfo->text_abs_x = textAbsX;
267 pDrawTextInfo->text_abs_y = textAbsY;
268 pDrawTextInfo->text_abs_baseline_y = textAbsBaselineY;
269
270 pDrawTextInfo->text_cur_x = textCurX;
271 pDrawTextInfo->text_cur_y = textCurY;
272 pDrawTextInfo->text_cur_baseline_y = textCurBaselineY;
273 pDrawTextInfo->text_cur_index = textCurIndex;
274 pDrawTextInfo->text_end_x = textEndX;
275 pDrawTextInfo->text_end_y = textEndY;
276 pDrawTextInfo->text_end_baseline_y = textEndBaselineY;
277 pDrawTextInfo->text_end_index = textEndIndex;
278
279 pDrawTextInfo->text_abs_min_lbearing = textAbsMinLBearing;
280 pDrawTextInfo->text_abs_max_rextra = textAbsMaxRExtra;
281 pDrawTextInfo->text_w = textW;
282 pDrawTextInfo->text_h = textH;
283
284 pDrawTextInfo->text_highlight = textHighlight;
285
286 pDrawTextInfo->cur_text_obj = curTextObj;
287
288 memcpy(&pDrawTextInfo->cur_text_obbox, &curTextOBBox, sizeof(struct BBRec));
289 memcpy(&pDrawTextInfo->cur_text_bbox, &curTextBBox, sizeof(struct BBRec));
290
291 pDrawTextInfo->cur_str_block = curStrBlock;
292 pDrawTextInfo->end_str_block = endStrBlock;
293 pDrawTextInfo->first_miniLine = firstMiniLine;
294 pDrawTextInfo->last_miniLine = lastMiniLine;
295
296 pDrawTextInfo->esc_pressed = escPressed;
297
298 pDrawTextInfo->cur_text_outline_w = curTextOutlineW;
299 pDrawTextInfo->cur_text_outline_half_w = curTextOutlineHalfW;
300
301 /* the following are from text.e */
302
303 pDrawTextInfo->text_drawn = textDrawn;
304 pDrawTextInfo->cur_text_modified = curTextModified;
305 pDrawTextInfo->text_vspace = textVSpace;
306
307 pDrawTextInfo->text_just = textJust;
308 pDrawTextInfo->text_cursor_shown = textCursorShown;
309 pDrawTextInfo->text_cursor_h = textCursorH;
310 pDrawTextInfo->editing_text = editingText;
311 pDrawTextInfo->cur_text_is_new = curTextIsNew;
312
313 pDrawTextInfo->edit_text_size = editTextSize;
314 }
315
RestoreDrawTextInfo(pDrawTextInfo)316 void RestoreDrawTextInfo(pDrawTextInfo)
317 DrawTextInfo *pDrawTextInfo;
318 {
319 memcpy(&gstTextHighlightInfo, &pDrawTextInfo->text_highlight_info,
320 sizeof(TextHighlightInfo));
321
322 textOrigX = pDrawTextInfo->text_orig_x;
323 textOrigY = pDrawTextInfo->text_orig_y;
324 textOrigBaselineY = pDrawTextInfo->text_orig_baseline_y;
325 textAbsX = pDrawTextInfo->text_abs_x;
326 textAbsY = pDrawTextInfo->text_abs_y;
327 textAbsBaselineY = pDrawTextInfo->text_abs_baseline_y;
328
329 textCurX = pDrawTextInfo->text_cur_x;
330 textCurY = pDrawTextInfo->text_cur_y;
331 textCurBaselineY = pDrawTextInfo->text_cur_baseline_y;
332 textCurIndex = pDrawTextInfo->text_cur_index;
333 textEndX = pDrawTextInfo->text_end_x;
334 textEndY = pDrawTextInfo->text_end_y;
335 textEndBaselineY = pDrawTextInfo->text_end_baseline_y;
336 textEndIndex = pDrawTextInfo->text_end_index;
337
338 textAbsMinLBearing = pDrawTextInfo->text_abs_min_lbearing;
339 textAbsMaxRExtra = pDrawTextInfo->text_abs_max_rextra;
340 textW = pDrawTextInfo->text_w;
341 textH = pDrawTextInfo->text_h;
342
343 textHighlight = pDrawTextInfo->text_highlight;
344
345 curTextObj = pDrawTextInfo->cur_text_obj;
346
347 memcpy(&curTextOBBox, &pDrawTextInfo->cur_text_obbox, sizeof(struct BBRec));
348 memcpy(&curTextBBox, &pDrawTextInfo->cur_text_bbox, sizeof(struct BBRec));
349
350 curStrBlock = pDrawTextInfo->cur_str_block;
351 endStrBlock = pDrawTextInfo->end_str_block;
352 firstMiniLine = pDrawTextInfo->first_miniLine;
353 lastMiniLine = pDrawTextInfo->last_miniLine;
354
355 escPressed = pDrawTextInfo->esc_pressed;
356
357 curTextOutlineW = pDrawTextInfo->cur_text_outline_w;
358 curTextOutlineHalfW = pDrawTextInfo->cur_text_outline_half_w;
359
360 /* the following are from text.e */
361
362 textDrawn = pDrawTextInfo->text_drawn;
363 curTextModified = pDrawTextInfo->cur_text_modified;
364 textVSpace = pDrawTextInfo->text_vspace;
365
366 textJust = pDrawTextInfo->text_just;
367 textCursorShown = pDrawTextInfo->text_cursor_shown;
368 textCursorH = pDrawTextInfo->text_cursor_h;
369 editingText = pDrawTextInfo->editing_text;
370 curTextIsNew = pDrawTextInfo->cur_text_is_new;
371
372 editTextSize = pDrawTextInfo->edit_text_size;
373 }
374
ResetDrawTextInfo()375 void ResetDrawTextInfo()
376 {
377 memset(&gstDrawTextInfo, 0, sizeof(DrawTextInfo));
378
379 RestoreDrawTextInfo(&gstDrawTextInfo);
380 }
381
SaveDrawWinDrawTextInfo(forced)382 void SaveDrawWinDrawTextInfo(forced)
383 int forced;
384 {
385 if (gstWBInfo.do_whiteboard) {
386 if (curChoice == DRAWTEXT) {
387 if (!forced && textCursorShown) {
388 PutTextCursor();
389 }
390 SaveDrawTextInfo(&gstDrawTextInfo);
391 gnDrawTextInfoValid = TRUE;
392 }
393 if (!forced) {
394 drawWinHasFocus = FALSE;
395 }
396 }
397 }
398
RestoreDrawWinDrawTextInfo(forced)399 void RestoreDrawWinDrawTextInfo(forced)
400 int forced;
401 {
402 if (!forced) {
403 drawWinHasFocus = TRUE;
404 }
405 if (gstWBInfo.do_whiteboard) {
406 if (gnDrawTextInfoValid && curChoice == DRAWTEXT) {
407 if (forced) {
408 RestoreDrawTextInfo(&gstDrawTextInfo);
409 }
410 if (!forced) {
411 gnDrawTextInfoValid = FALSE;
412 if (textCursorShown) {
413 PutTextCursor();
414 }
415 }
416 }
417 }
418 }
419
420 /* --------------------- DirtyBBox Functions --------------------- */
421
422 static DirtyBBoxInfo gstDirtyBBoxInfo;
423
ResetDirtyBBoxInfo()424 void ResetDirtyBBoxInfo()
425 {
426 memset(&gstDirtyBBoxInfo, 0, sizeof(DirtyBBoxInfo));
427 gstDirtyBBoxInfo.valid = FALSE;
428 gstDirtyBBoxInfo.force_redraw_all = FALSE;
429 }
430
AddToDirtyBBox(pBBox)431 void AddToDirtyBBox(pBBox)
432 struct BBRec *pBBox;
433 {
434 if (gstDirtyBBoxInfo.valid) {
435 UnionRect(&gstDirtyBBoxInfo.bbox, pBBox, &gstDirtyBBoxInfo.bbox);
436 } else {
437 gstDirtyBBoxInfo.valid = TRUE;
438 memcpy(&gstDirtyBBoxInfo.bbox, pBBox, sizeof(struct BBRec));
439 }
440 }
441
ForceDirtyBBoxToRedrawAll()442 void ForceDirtyBBoxToRedrawAll()
443 {
444 gstDirtyBBoxInfo.force_redraw_all = TRUE;
445 }
446
GetDirtyBBox(pBBox)447 int GetDirtyBBox(pBBox)
448 struct BBRec *pBBox;
449 {
450 if (pBBox != NULL) {
451 if (gstDirtyBBoxInfo.valid) {
452 memcpy(pBBox, &gstDirtyBBoxInfo.bbox, sizeof(struct BBRec));
453 } else {
454 memset(pBBox, 0, sizeof(struct BBRec));
455 }
456 }
457 return (gstDirtyBBoxInfo.valid && !gstDirtyBBoxInfo.force_redraw_all);
458 }
459
460 static
IntersectDirtyBBox(pBBox)461 int IntersectDirtyBBox(pBBox)
462 struct BBRec *pBBox;
463 {
464 return BBoxIntersect(*pBBox, gstDirtyBBoxInfo.bbox);
465 }
466
467 /* --------------------- Indent Functions --------------------- */
468
469 static char **gaszIndentStrings=NULL;
470 static int gnMaxIndent=0;
471
CleanUpIndentStrings()472 void CleanUpIndentStrings()
473 {
474 if (gaszIndentStrings != NULL) {
475 int i=0;
476
477 for (i=0; i < gnMaxIndent; i++) {
478 UtilFree(gaszIndentStrings[i]);
479 }
480 free(gaszIndentStrings);
481 }
482 gaszIndentStrings = NULL;
483 gnMaxIndent = 0;
484 }
485
486 static
InitIndentStrings()487 void InitIndentStrings()
488 {
489 gaszIndentStrings = NULL;
490 gnMaxIndent = 0;
491 }
492
GetIndentString(indent)493 char *GetIndentString(indent)
494 int indent;
495 {
496 int i=0;
497
498 if (indent < 0) return NULL;
499 if (indent == 0) return "";
500
501 if (gaszIndentStrings == NULL) {
502 gaszIndentStrings = (char**)malloc(indent*sizeof(char*));
503 if (gaszIndentStrings == NULL) FailAllocMessage();
504 memset(gaszIndentStrings, 0, indent*sizeof(char*));
505 gnMaxIndent = indent;
506 } else if (indent > gnMaxIndent) {
507 gaszIndentStrings = (char**)realloc(gaszIndentStrings,
508 indent*sizeof(char*));
509 if (gaszIndentStrings == NULL) FailAllocMessage();
510 for (i=gnMaxIndent; i < indent; i++) {
511 gaszIndentStrings[i] = NULL;
512 }
513 gnMaxIndent = indent;
514 } else {
515 if (gaszIndentStrings[indent-1] != NULL) {
516 return gaszIndentStrings[indent-1];
517 }
518 }
519 gaszIndentStrings[indent-1] = (char*)malloc((indent+1)*sizeof(char));
520 if (gaszIndentStrings[indent-1] == NULL) FailAllocMessage();
521 memset(gaszIndentStrings[indent-1], 0, sizeof((indent+1)*sizeof(char)));
522
523 for (i=0; i < indent; i++) {
524 gaszIndentStrings[indent-1][i] = ' ';
525 }
526 gaszIndentStrings[indent-1][i] = '\0';
527
528 return gaszIndentStrings[indent-1];
529 }
530
DumpIndentString(FP,indent)531 void DumpIndentString(FP, indent)
532 FILE *FP;
533 int indent;
534 {
535 char *psz=GetIndentString(indent);
536
537 if (psz != NULL) {
538 fprintf(FP, "%s", psz);
539 }
540 }
541
542 /* --------------------- Init Functions --------------------- */
543
CleanUpMiniLines()544 void CleanUpMiniLines()
545 {
546 CleanUpIndentStrings();
547 memset(&gstDrawTextInfo, 0, sizeof(DrawTextInfo));
548 gnDrawTextInfoValid = FALSE;
549 }
550
InitMiniLines()551 int InitMiniLines()
552 {
553 InitIndentStrings();
554 memset(&gstDrawTextInfo, 0, sizeof(DrawTextInfo));
555 gnDrawTextInfoValid = FALSE;
556
557 return TRUE;
558 }
559
560 /* --------------------- Free Functions --------------------- */
561
FreeStrSeg(pStrSeg)562 void FreeStrSeg(pStrSeg)
563 StrSegInfo *pStrSeg;
564 {
565 if (pStrSeg->font_name != NULL) free(pStrSeg->font_name);
566 if (pStrSeg->dyn_str.s != NULL) free(pStrSeg->dyn_str.s);
567 free(pStrSeg);
568 }
569
FreeStrBlock(pStrBlock)570 void FreeStrBlock(pStrBlock)
571 StrBlockInfo *pStrBlock;
572 {
573 switch (pStrBlock->type) {
574 case SB_SIMPLE:
575 FreeStrSeg(pStrBlock->seg);
576 break;
577 case SB_SUPSUB_LEFT:
578 case SB_SUPSUB_CENTER:
579 case SB_SUPSUB_RIGHT:
580 if (pStrBlock->sup != NULL) FreeMiniLines(pStrBlock->sup, TRUE);
581 if (pStrBlock->sub != NULL) FreeMiniLines(pStrBlock->sub, TRUE);
582 if (pStrBlock->type == SB_SUPSUB_CENTER) FreeStrSeg(pStrBlock->seg);
583 break;
584 }
585 free(pStrBlock);
586 }
587
FreeMiniLine(pMiniLine)588 void FreeMiniLine(pMiniLine)
589 MiniLineInfo *pMiniLine;
590 {
591 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
592
593 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
594 pStrBlock=pNextStrBlock) {
595 pNextStrBlock = pStrBlock->next;
596 FreeStrBlock(pStrBlock);
597 }
598 free(pMiniLine);
599 }
600
FreeMiniLines(minilines,free_minilines)601 void FreeMiniLines(minilines, free_minilines)
602 MiniLinesInfo *minilines;
603 int free_minilines;
604 {
605 MiniLineInfo *pMiniLine=NULL, *pNextMiniLine=NULL;
606
607 for (pMiniLine=minilines->first; pMiniLine != NULL;
608 pMiniLine=pNextMiniLine) {
609 pNextMiniLine = pMiniLine->next;
610 FreeMiniLine(pMiniLine);
611 }
612 if (free_minilines) {
613 free(minilines);
614 } else {
615 minilines->first = minilines->last = NULL;
616 }
617 }
618
FreeStrBlockList(pFirstStrBlock)619 void FreeStrBlockList(pFirstStrBlock)
620 StrBlockInfo *pFirstStrBlock;
621 {
622 StrBlockInfo *pNextStrBlock=NULL;
623
624 while (pFirstStrBlock != NULL) {
625 pNextStrBlock = pFirstStrBlock->next;
626 FreeStrBlock(pFirstStrBlock);
627 pFirstStrBlock = pNextStrBlock;
628 }
629 }
630
FreeMiniLineList(pFirstMiniLine)631 void FreeMiniLineList(pFirstMiniLine)
632 MiniLineInfo *pFirstMiniLine;
633 {
634 MiniLineInfo *pNextMiniLine=NULL;
635
636 while (pFirstMiniLine != NULL) {
637 pNextMiniLine = pFirstMiniLine->next;
638 FreeMiniLine(pFirstMiniLine);
639 pFirstMiniLine = pNextMiniLine;
640 }
641 }
642
UnlinkStrBlock(pStrBlock)643 void UnlinkStrBlock(pStrBlock)
644 StrBlockInfo *pStrBlock;
645 {
646 MiniLineInfo *pOwnerMiniLine=pStrBlock->owner_mini_line;
647
648 if (pStrBlock->prev == NULL) {
649 pOwnerMiniLine->first_block = pStrBlock->next;
650 } else {
651 pStrBlock->prev->next = pStrBlock->next;
652 }
653 if (pStrBlock->next == NULL) {
654 pOwnerMiniLine->last_block = pStrBlock->prev;
655 } else {
656 pStrBlock->next->prev = pStrBlock->prev;
657 }
658 pStrBlock->prev = pStrBlock->next = NULL;
659 }
660
UnlinkMiniLine(pMiniLine)661 void UnlinkMiniLine(pMiniLine)
662 MiniLineInfo *pMiniLine;
663 {
664 MiniLinesInfo *pOwnerMiniLines=pMiniLine->owner_minilines;
665
666 if (pMiniLine->prev == NULL) {
667 pOwnerMiniLines->first = pMiniLine->next;
668 } else {
669 pMiniLine->prev->next = pMiniLine->next;
670 }
671 if (pMiniLine->next == NULL) {
672 pOwnerMiniLines->last = pMiniLine->prev;
673 } else {
674 pMiniLine->next->prev = pMiniLine->prev;
675 }
676 pMiniLine->prev = pMiniLine->next = NULL;
677 }
678
NewStrSeg()679 StrSegInfo *NewStrSeg()
680 {
681 StrSegInfo *pStrSeg=(StrSegInfo*)malloc(sizeof(StrSegInfo));
682
683 if (pStrSeg == NULL) FailAllocMessage();
684 memset(pStrSeg, 0, sizeof(StrSegInfo));
685 DynStrSet(&pStrSeg->dyn_str, "");
686 return pStrSeg;
687 }
688
NewStrBlock()689 StrBlockInfo *NewStrBlock()
690 {
691 StrBlockInfo *pStrBlock=(StrBlockInfo*)malloc(sizeof(StrBlockInfo));
692
693 if (pStrBlock == NULL) FailAllocMessage();
694 memset(pStrBlock, 0, sizeof(StrBlockInfo));
695 return pStrBlock;
696 }
697
NewMiniLine()698 MiniLineInfo *NewMiniLine()
699 {
700 MiniLineInfo *pMiniLine=(MiniLineInfo*)malloc(sizeof(MiniLineInfo));
701
702 if (pMiniLine == NULL) FailAllocMessage();
703 memset(pMiniLine, 0, sizeof(MiniLineInfo));
704 return pMiniLine;
705 }
706
NewMiniLines()707 MiniLinesInfo *NewMiniLines()
708 {
709 MiniLinesInfo *minilines=(MiniLinesInfo*)malloc(sizeof(MiniLinesInfo));
710
711 if (minilines == NULL) FailAllocMessage();
712 memset(minilines, 0, sizeof(MiniLinesInfo));
713 return minilines;
714 }
715
InsertStrBlock(pPrevStrBlock,pNextStrBlock,pStrBlock,ppFirstStrBlock,ppLastStrBlock)716 void InsertStrBlock(pPrevStrBlock, pNextStrBlock, pStrBlock,
717 ppFirstStrBlock, ppLastStrBlock)
718 StrBlockInfo *pPrevStrBlock, *pNextStrBlock, *pStrBlock;
719 StrBlockInfo **ppFirstStrBlock, **ppLastStrBlock;
720 {
721 pStrBlock->prev = pPrevStrBlock;
722 pStrBlock->next = pNextStrBlock;
723
724 if (pPrevStrBlock == NULL) {
725 (*ppFirstStrBlock) = pStrBlock;
726 } else {
727 pPrevStrBlock->next = pStrBlock;
728 }
729 if (pNextStrBlock == NULL) {
730 (*ppLastStrBlock) = pStrBlock;
731 } else {
732 pNextStrBlock->prev = pStrBlock;
733 }
734 }
735
InsertMiniLine(pPrevMiniLine,pNextMiniLine,pMiniLine,ppFirstMiniLine,ppLastMiniLine)736 void InsertMiniLine(pPrevMiniLine, pNextMiniLine, pMiniLine,
737 ppFirstMiniLine, ppLastMiniLine)
738 MiniLineInfo *pPrevMiniLine, *pNextMiniLine, *pMiniLine;
739 MiniLineInfo **ppFirstMiniLine, **ppLastMiniLine;
740 {
741 pMiniLine->prev = pPrevMiniLine;
742 pMiniLine->next = pNextMiniLine;
743
744 if (pPrevMiniLine == NULL) {
745 (*ppFirstMiniLine) = pMiniLine;
746 } else {
747 pPrevMiniLine->next = pMiniLine;
748 }
749 if (pNextMiniLine == NULL) {
750 (*ppLastMiniLine) = pMiniLine;
751 } else {
752 pNextMiniLine->prev = pMiniLine;
753 }
754 }
755
BlankStrSeg(pStrSeg)756 int BlankStrSeg(pStrSeg)
757 StrSegInfo *pStrSeg;
758 {
759 return (*pStrSeg->dyn_str.s == '\0');
760 }
761
BlankStrBlock(pStrBlock)762 int BlankStrBlock(pStrBlock)
763 StrBlockInfo *pStrBlock;
764 {
765 switch (pStrBlock->type) {
766 case SB_SIMPLE: return BlankStrSeg(pStrBlock->seg);
767
768 case SB_CHAR_SPACE: return (pStrBlock->special_char_w == 0);
769
770 case SB_SUPSUB_LEFT:
771 case SB_SUPSUB_CENTER:
772 case SB_SUPSUB_RIGHT:
773 if (pStrBlock->sup != NULL) {
774 if (!BlankMiniLines(pStrBlock->sup)) {
775 return FALSE;
776 }
777 }
778 if (pStrBlock->sub != NULL) {
779 if (!BlankMiniLines(pStrBlock->sub)) {
780 return FALSE;
781 }
782 }
783 if (pStrBlock->type == SB_SUPSUB_CENTER) {
784 return BlankStrSeg(pStrBlock->seg);
785 }
786 break;
787 }
788 return TRUE;
789 }
790
BlankMiniLine(pMiniLine)791 int BlankMiniLine(pMiniLine)
792 MiniLineInfo *pMiniLine;
793 {
794 StrBlockInfo *pStrBlock=NULL;
795
796 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
797 pStrBlock=pStrBlock->next) {
798 if (!BlankStrBlock(pStrBlock)) {
799 return FALSE;
800 }
801 }
802 return TRUE;
803 }
804
BlankMiniLines(minilines)805 int BlankMiniLines(minilines)
806 MiniLinesInfo *minilines;
807 {
808 MiniLineInfo *pMiniLine=NULL;
809
810 for (pMiniLine=minilines->first; pMiniLine != NULL;
811 pMiniLine=pMiniLine->next) {
812 if (!BlankMiniLine(pMiniLine)) {
813 return FALSE;
814 }
815 }
816 return TRUE;
817 }
818
GetTextFirstStrSeg(obj_ptr)819 StrSegInfo *GetTextFirstStrSeg(obj_ptr)
820 struct ObjRec *obj_ptr;
821 {
822 StrBlockInfo *pStrBlock=obj_ptr->detail.t->minilines.first->first_block;
823
824 for ( ; pStrBlock != NULL; pStrBlock=pStrBlock->next) {
825 if (pStrBlock->type == SB_SIMPLE) {
826 return (pStrBlock->seg);
827 }
828 }
829 return NULL;
830 }
831
GetTextFirstDynStr(obj_ptr)832 struct DynStrRec *GetTextFirstDynStr(obj_ptr)
833 struct ObjRec *obj_ptr;
834 {
835 StrBlockInfo *pStrBlock=obj_ptr->detail.t->minilines.first->first_block;
836
837 for ( ; pStrBlock != NULL; pStrBlock=pStrBlock->next) {
838 if (pStrBlock->type == SB_SIMPLE) {
839 return (&pStrBlock->seg->dyn_str);
840 }
841 }
842 return NULL;
843 }
844
845 /* ===================== TextRec Routines ===================== */
846
CopyCurInfoIntoStrSeg(pStrBlock,pStrSeg)847 void CopyCurInfoIntoStrSeg(pStrBlock, pStrSeg)
848 StrBlockInfo *pStrBlock;
849 StrSegInfo *pStrSeg;
850 {
851 pStrSeg->color = colorIndex;
852 UtilStrCpyN(pStrSeg->color_str, sizeof(pStrSeg->color_str),
853 colorMenuItems[colorIndex]);
854 pStrSeg->font = curFont;
855 pStrSeg->style = curStyle;
856 pStrSeg->sz_unit = curSzUnit;
857 pStrSeg->double_byte = canvasFontDoubleByte;
858 pStrSeg->double_byte_mod_bytes = canvasFontDoubleByteModBytes;
859 pStrSeg->double_byte_vertical = canvasFontDoubleByteVertical;
860 pStrSeg->direction = canvasFontDirection;
861 pStrSeg->dontreencode = canvasFontDontReencode;
862 pStrSeg->underline_on = curUnderlineOn;
863 pStrSeg->overline_on = curOverlineOn;
864 pStrSeg->asc = canvasFontAsc;
865 pStrSeg->des = canvasFontDes;
866 /*
867 * The following are set in RecalcTextMetrics():
868 * w, min_lbearing, max_rextra
869 */
870 /*
871 * If read_only is TRUE, the following are set in ReadTextObj():
872 * read_only, orig_w, orig_h, orig_asc, orig_des
873 */
874 /*
875 * These fields are not touched: font_name, dyn_str, owner
876 */
877 }
878
CopyCurInfoFromStrSeg(pStrSeg)879 void CopyCurInfoFromStrSeg(pStrSeg)
880 StrSegInfo *pStrSeg;
881 {
882 colorIndex = pStrSeg->color;
883 curFont = pStrSeg->font;
884 curStyle = pStrSeg->style;
885 curSzUnit = pStrSeg->sz_unit;
886 if (PRTGIF) {
887 canvasFontDoubleByte = pStrSeg->double_byte;
888 canvasFontDoubleByteModBytes = pStrSeg->double_byte_mod_bytes;
889 canvasFontDoubleByteVertical = pStrSeg->double_byte_vertical;
890 canvasFontDirection = pStrSeg->direction;
891 canvasFontDontReencode = pStrSeg->dontreencode;
892 canvasFontAsc = pStrSeg->asc;
893 canvasFontDes = pStrSeg->des;
894 } else {
895 SetCanvasFont();
896 }
897 curUnderlineOn = pStrSeg->underline_on;
898 curOverlineOn = pStrSeg->overline_on;
899 }
900
CopyCurInfoIntoTextPtr(obj_ptr,text_ptr)901 void CopyCurInfoIntoTextPtr(obj_ptr, text_ptr)
902 struct ObjRec *obj_ptr;
903 struct TextRec *text_ptr;
904 {
905 obj_ptr->trans_pat = transPat;
906
907 text_ptr->minilines.just = textJust;
908 text_ptr->minilines.v_space = textVSpace;
909 text_ptr->pen = penPat;
910 text_ptr->fill = objFill;
911 text_ptr->minilines.first->asc = canvasLineAsc;
912 text_ptr->minilines.first->des = canvasLineDes;
913 text_ptr->underline_y_offset = curUnderlineYOffset;
914 text_ptr->overline_y_offset = curOverlineYOffset;
915
916 /*
917 * The following are set in RecalcTextMetrics():
918 * w, h, min_lbearing, max_rextra
919 */
920 text_ptr->w = 0;
921 text_ptr->h = 0;
922 text_ptr->min_lbearing = 0;
923 text_ptr->max_rextra = 0;
924
925 /*
926 * If read_only is TRUE, the following are set in ReadTextObj():
927 * read_only, orig_w, orig_h, orig_asc, orig_des
928 */
929 text_ptr->read_only = FALSE;
930 text_ptr->orig_w = text_ptr->orig_h = 0;
931
932 /*
933 * The following fields are not touched: cached_ctm, orig_bbox, baseline_y,
934 * cached_bitmap, cached_zoom, cached_zoomed.
935 */
936 }
937
CopyCurInfoFromTextPtr(obj_ptr,text_ptr)938 void CopyCurInfoFromTextPtr(obj_ptr, text_ptr)
939 struct ObjRec *obj_ptr;
940 struct TextRec *text_ptr;
941 {
942 transPat = obj_ptr->trans_pat;
943
944 textJust = text_ptr->minilines.just;
945 textVSpace = text_ptr->minilines.v_space;
946 penPat = text_ptr->pen;
947 objFill = text_ptr->fill;
948 canvasLineAsc = text_ptr->minilines.first->asc;
949 canvasLineDes = text_ptr->minilines.first->des;
950 curUnderlineYOffset = text_ptr->underline_y_offset;
951 curOverlineYOffset = text_ptr->overline_y_offset;
952 }
953
954 /* ===================== RecalcTextMetrics() ===================== */
955
956 static
RecalcStrSegMetrics(pStrSeg,prmi)957 int RecalcStrSegMetrics(pStrSeg, prmi)
958 StrSegInfo *pStrSeg;
959 RecalcMetricsInfo *prmi;
960 /*
961 * This function recomputes text metrics of the string segments pStrSeg.
962 * Returns FALSE if the block is read_only.
963 */
964 {
965 int read_only=FALSE;
966 XCharStruct xcs;
967
968 curFont = pStrSeg->font;
969 curStyle = pStrSeg->style;
970 curSzUnit = pStrSeg->sz_unit;
971
972 if (mainDisplay == NULL) return FALSE;
973
974 SetCanvasFont();
975 if (SzUnitToFontSize(curSzUnit) != canvasFontSize) {
976 #ifdef _TGIF_DBG /* debug, do not translate */
977 fprintf(stderr, "RecalcStrSegMetrics(): read_only detected.\n");
978 #endif /* _TGIF_DBG */
979 read_only = TRUE;
980 } else {
981 MyTextExtents(canvasFontPtr, pStrSeg->dyn_str.s, pStrSeg->dyn_str.sz-1,
982 &xcs);
983
984 pStrSeg->w = xcs.width;
985 pStrSeg->min_lbearing = (xcs.lbearing >= 0 ? 0 : xcs.lbearing);
986 pStrSeg->max_rextra = xcs.rbearing-xcs.width;
987 pStrSeg->asc = canvasFontAsc;
988 pStrSeg->des = canvasFontDes;
989 }
990 if (read_only && readingTextObject) {
991 pStrSeg->read_only = TRUE;
992 }
993 return (!read_only);
994 }
995
996 static
UpdateMetricsFromValues(p_found,w,asc,des,min_lbearing,max_rextra,pTextExtents)997 void UpdateMetricsFromValues(p_found, w, asc, des, min_lbearing, max_rextra,
998 pTextExtents)
999 int *p_found, w, asc, des, min_lbearing, max_rextra;
1000 TextExtentsInfo *pTextExtents;
1001 {
1002 if (p_found == NULL || !(*p_found)) {
1003 pTextExtents->w = w;
1004 pTextExtents->lbearing = min_lbearing;
1005 pTextExtents->rextra = max_rextra;
1006 pTextExtents->asc = asc;
1007 pTextExtents->des = des;
1008 if (p_found != NULL) *p_found = TRUE;
1009 } else {
1010 if (w > (pTextExtents->w)) pTextExtents->w = w;
1011 if (min_lbearing > (pTextExtents->lbearing)) {
1012 pTextExtents->lbearing = min_lbearing;
1013 }
1014 if (max_rextra > (pTextExtents->rextra)) {
1015 pTextExtents->rextra = max_rextra;
1016 }
1017 if (asc > pTextExtents->asc) {
1018 pTextExtents->asc = asc;
1019 }
1020 if (des > pTextExtents->des) {
1021 pTextExtents->des = des;
1022 }
1023 }
1024 pTextExtents->bbox_w = pTextExtents->w - pTextExtents->lbearing +
1025 pTextExtents->rextra;
1026 pTextExtents->bbox_h = pTextExtents->asc + pTextExtents->des;
1027 }
1028
1029 static
UpdateMetricsFromStrSegInfo(p_found,pStrSeg,pTextExtents)1030 void UpdateMetricsFromStrSegInfo(p_found, pStrSeg, pTextExtents)
1031 int *p_found;
1032 StrSegInfo *pStrSeg;
1033 TextExtentsInfo *pTextExtents;
1034 {
1035 UpdateMetricsFromValues(p_found, pStrSeg->w, pStrSeg->asc, pStrSeg->des,
1036 pStrSeg->min_lbearing, pStrSeg->max_rextra, pTextExtents);
1037 }
1038
1039 static
StrBlockTypeToMiniLinesJust(type)1040 int StrBlockTypeToMiniLinesJust(type)
1041 int type;
1042 {
1043 switch (type) {
1044 case SB_SUPSUB_LEFT: return JUST_R;
1045 case SB_SUPSUB_CENTER: return JUST_C;
1046 case SB_SUPSUB_RIGHT: return JUST_L;
1047 }
1048 return JUST_L;
1049 }
1050
1051 static
RecalcStrBlockMetrics(pStrBlock,prmi)1052 int RecalcStrBlockMetrics(pStrBlock, prmi)
1053 StrBlockInfo *pStrBlock;
1054 RecalcMetricsInfo *prmi;
1055 /*
1056 * This function recursively recomputes all text metrics of the
1057 * string segments and mini-lines in pStrBlock.
1058 * Returns FALSE if the block is read_only.
1059 */
1060 {
1061 int found=FALSE, saved_baseline_y=prmi->baseline_y;
1062 int read_only=FALSE;
1063 TextExtentsInfo stTextExtents;
1064
1065 pStrBlock->depth = prmi->depth;
1066 pStrBlock->pre_order = (prmi->pre_order)++;
1067
1068 memset(&stTextExtents, 0, sizeof(TextExtentsInfo));
1069 switch (pStrBlock->type) {
1070 case SB_SIMPLE:
1071 /*
1072 * For a simple block, the block only contains a string segment.
1073 * Other than the vertical offset, the metrics between the string
1074 * segment and this block are identical.
1075 */
1076 pStrBlock->seg->owner = pStrBlock;
1077 if (!dontRecalcStrSegMetrics) {
1078 if (!RecalcStrSegMetrics(pStrBlock->seg, prmi)) {
1079 read_only = TRUE;
1080 }
1081 }
1082 UpdateMetricsFromStrSegInfo(NULL, pStrBlock->seg, &stTextExtents);
1083 break;
1084 /*
1085 * Special characters are very much like simple blocks, except for
1086 * the differences noted below.
1087 */
1088 case SB_CHAR_SPACE:
1089 /*
1090 * The space character is not the same as (char*)0x20. It's used for
1091 * ``extra space'' or ``negative space''. The width of it is
1092 * in special_char_w. All other metrics are 0. Since it
1093 * doesn't have an ascent, its vertical offset from the parent
1094 * block is meaningless.
1095 */
1096 stTextExtents.w = pStrBlock->special_char_w;
1097 stTextExtents.lbearing = stTextExtents.rextra = 0;
1098 stTextExtents.asc = stTextExtents.des = 0;
1099 break;
1100 case SB_SUPSUB_LEFT:
1101 case SB_SUPSUB_CENTER:
1102 case SB_SUPSUB_RIGHT:
1103 prmi->depth++;
1104 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1105 /* pStrBlock->seg better not be NULL or it will crash */
1106 pStrBlock->depth = prmi->depth;
1107 pStrBlock->seg->owner = pStrBlock;
1108 if (!dontRecalcStrSegMetrics) {
1109 if (!RecalcStrSegMetrics(pStrBlock->seg, prmi)) {
1110 read_only = TRUE;
1111 }
1112 }
1113 UpdateMetricsFromStrSegInfo(&found, pStrBlock->seg, &stTextExtents);
1114 }
1115 if (pStrBlock->sup != NULL) {
1116 MiniLinesInfo *minilines=pStrBlock->sup;
1117 int asc=0, des=0;
1118
1119 pStrBlock->sup->owner_block = pStrBlock;
1120
1121 prmi->baseline_y = saved_baseline_y+minilines->baseline_offset;
1122 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1123 /*
1124 * Note, by default, for SB_SUPSUB_CENTER,
1125 * minilines.baseline_offset is the descent of the
1126 * superscript font. Adding the ascent of the font for
1127 * the string segment below makes the superscript sits
1128 * right on top of the string segment.
1129 * Doing it this way, when you change the font of the string
1130 * segment, the relative position of the superscript and
1131 * the string segment doesn't change.
1132 */
1133 prmi->baseline_y -= pStrBlock->seg->asc;
1134 }
1135 if (!RecalcMiniLinesMetrics(minilines, prmi)) {
1136 read_only = TRUE;
1137 }
1138 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1139 asc = (-minilines->baseline_offset) + minilines->first->asc +
1140 pStrBlock->seg->asc;
1141 des = minilines->h - asc;
1142 } else {
1143 asc = (-minilines->baseline_offset) + minilines->first->asc;
1144 des = minilines->h - asc;
1145 }
1146 UpdateMetricsFromValues(&found, minilines->w, asc, des,
1147 minilines->min_lbearing, minilines->max_rextra, &stTextExtents);
1148
1149 minilines->just = StrBlockTypeToMiniLinesJust(pStrBlock->type);
1150 }
1151 if (pStrBlock->sub != NULL) {
1152 MiniLinesInfo *minilines=pStrBlock->sub;
1153 int asc=0, des=0;
1154
1155 pStrBlock->sub->owner_block = pStrBlock;
1156
1157 prmi->baseline_y = saved_baseline_y+pStrBlock->sub->baseline_offset;
1158 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1159 /*
1160 * Note, by default, for SB_SUPSUB_CENTER,
1161 * pStrBlock->sub->baseline_offset is the ascent of the
1162 * subscript font. Adding the descent of the font for
1163 * the string segment below makes the subscript sits
1164 * right below the string segment.
1165 * Doing it this way, when you change the font of the string
1166 * segment, the relative position of the subscript and
1167 * the string segment doesn't change.
1168 */
1169 prmi->baseline_y += pStrBlock->seg->des;
1170 }
1171 if (!RecalcMiniLinesMetrics(minilines, prmi)) {
1172 read_only = TRUE;
1173 }
1174 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1175 asc = minilines->first->asc - minilines->baseline_offset -
1176 pStrBlock->seg->des;
1177 des = minilines->h - asc;
1178 } else {
1179 asc = minilines->first->asc - minilines->baseline_offset;
1180 des = minilines->h - asc;
1181 }
1182 UpdateMetricsFromValues(&found, minilines->w, asc, des,
1183 minilines->min_lbearing, minilines->max_rextra, &stTextExtents);
1184
1185 minilines->just = StrBlockTypeToMiniLinesJust(pStrBlock->type);
1186 }
1187 prmi->depth--;
1188 break;
1189 }
1190 pStrBlock->w = stTextExtents.w;
1191 pStrBlock->min_lbearing = stTextExtents.lbearing;
1192 pStrBlock->max_rextra = stTextExtents.rextra;
1193 pStrBlock->asc = stTextExtents.asc;
1194 pStrBlock->des = stTextExtents.des;
1195
1196 prmi->baseline_y = saved_baseline_y;
1197 if (read_only && readingTextObject) {
1198 pStrBlock->read_only = TRUE;
1199 }
1200 return (!read_only);
1201 }
1202
RecalcMiniLineMetrics(pMiniLine,prmi)1203 int RecalcMiniLineMetrics(pMiniLine, prmi)
1204 MiniLineInfo *pMiniLine;
1205 RecalcMetricsInfo *prmi;
1206 /*
1207 * This function recursively recomputes all text metrics of the
1208 * blocks in pMiniLine.
1209 * Returns FALSE if the text is read_only.
1210 */
1211 {
1212 StrBlockInfo *pStrBlock=NULL;
1213 int min_lbearing=0, max_rextra=0, max_asc=0, max_des=0;
1214 int saved_baseline_y=prmi->baseline_y;
1215 int saved_x=prmi->x, read_only=FALSE;
1216
1217 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
1218 pStrBlock=pStrBlock->next) {
1219 pStrBlock->owner_mini_line = pMiniLine;
1220
1221 if (!RecalcStrBlockMetrics(pStrBlock, prmi)) {
1222 read_only = FALSE;
1223 }
1224 if (pStrBlock->asc > max_asc) max_asc = pStrBlock->asc;
1225 if (pStrBlock->des > max_des) max_des = pStrBlock->des;
1226 if (pStrBlock->min_lbearing < min_lbearing) {
1227 min_lbearing = pStrBlock->min_lbearing;
1228 }
1229 if (pStrBlock->max_rextra > max_rextra) {
1230 max_rextra = pStrBlock->max_rextra;
1231 }
1232 prmi->x += pStrBlock->w;
1233 }
1234 pMiniLine->w = prmi->x - saved_x;
1235 pMiniLine->min_lbearing = min_lbearing;
1236 pMiniLine->max_rextra = max_rextra;
1237 pMiniLine->asc = max_asc;
1238 pMiniLine->des = max_des;
1239
1240 prmi->x = saved_x;
1241 prmi->baseline_y = saved_baseline_y;
1242
1243 if (read_only && readingTextObject) {
1244 pMiniLine->read_only = TRUE;
1245 }
1246 return (!read_only);
1247 }
1248
RecalcMiniLinesMetrics(minilines,prmi)1249 int RecalcMiniLinesMetrics(minilines, prmi)
1250 MiniLinesInfo *minilines;
1251 RecalcMetricsInfo *prmi;
1252 /*
1253 * This function recursively recomputes all text metrics of the minilines.
1254 * Returns FALSE if the text is read_only.
1255 */
1256 {
1257 MiniLineInfo *pMiniLine=NULL;
1258 int v_space=minilines->v_space;
1259 int saved_x=prmi->x, saved_baseline_y=prmi->baseline_y;
1260 int min_y=prmi->baseline_y, max_y=prmi->baseline_y;
1261 int max_w=0, min_lbearing=0, max_rextra=0;
1262 int read_only=FALSE, saved_depth=prmi->depth;
1263
1264 for (pMiniLine=minilines->first; pMiniLine != NULL;
1265 pMiniLine=pMiniLine->next) {
1266 pMiniLine->owner_minilines = minilines;
1267
1268 #ifdef _TGIF_DBG /* debug, do not translate */
1269 if (pMiniLine == minilines->first) {
1270 TgAssert(pMiniLine->v_gap == 0,
1271 "First mini_line has non-zero v_gap in RecalcMiniLinesMetrics()",
1272 NULL);
1273 }
1274 #endif /* _TGIF_DBG */
1275 prmi->baseline_y += pMiniLine->v_gap;
1276 if (!RecalcMiniLineMetrics(pMiniLine, prmi)) {
1277 read_only = TRUE;
1278 }
1279 if (pMiniLine != minilines->first) {
1280 prmi->baseline_y += pMiniLine->asc;
1281 }
1282 if (prmi->baseline_y-pMiniLine->asc < min_y) {
1283 min_y = prmi->baseline_y-pMiniLine->asc;
1284 }
1285 if (prmi->baseline_y+pMiniLine->des > max_y) {
1286 max_y = prmi->baseline_y+pMiniLine->des;
1287 }
1288 if (pMiniLine->min_lbearing < min_lbearing) {
1289 min_lbearing = pMiniLine->min_lbearing;
1290 }
1291 if (pMiniLine->max_rextra > max_rextra) {
1292 max_rextra = pMiniLine->max_rextra;
1293 }
1294 if (pMiniLine->w > max_w) max_w = pMiniLine->w;
1295
1296 prmi->baseline_y += pMiniLine->des + v_space;
1297 }
1298 minilines->w = max_w;
1299 minilines->h = max_y-min_y;
1300 if (minilines->h < 0) minilines->h = min_y-max_y;
1301 minilines->min_lbearing = min_lbearing;
1302 minilines->max_rextra = max_rextra;
1303
1304 prmi->x = saved_x;
1305 prmi->baseline_y = saved_baseline_y;
1306 prmi->depth = saved_depth;
1307
1308 if (read_only && readingTextObject) {
1309 minilines->read_only = TRUE;
1310 }
1311 return (!read_only);
1312 }
1313
RecalcTextMetrics(text_ptr,x,orig_baseline_y)1314 int RecalcTextMetrics(text_ptr, x, orig_baseline_y)
1315 struct TextRec *text_ptr;
1316 int x, orig_baseline_y;
1317 /*
1318 * Returns FALSE if the text is read_only.
1319 */
1320 {
1321 MiniLinesInfo *minilines=(&text_ptr->minilines);
1322 int read_only=FALSE;
1323 RecalcMetricsInfo rmi;
1324
1325 if (text_ptr->read_only) return FALSE;
1326
1327 memset(&rmi, 0, sizeof(RecalcMetricsInfo));
1328 rmi.x = rmi.orig_x = x;
1329 rmi.baseline_y = rmi.orig_baseline_y = orig_baseline_y;
1330
1331 PushCurFont();
1332 if (!RecalcMiniLinesMetrics(minilines, &rmi)) {
1333 read_only = TRUE;
1334 }
1335 PopCurFont();
1336
1337 text_ptr->w = minilines->w;
1338 text_ptr->h = minilines->h;
1339 text_ptr->min_lbearing = minilines->min_lbearing;
1340 text_ptr->max_rextra = minilines->max_rextra;
1341 text_ptr->lines = GetNumberOfMiniLines(minilines);
1342
1343 if (read_only && readingTextObject) {
1344 text_ptr->read_only = TRUE;
1345 }
1346 return (!read_only);
1347 }
1348
1349 /* --------------------- UpdateCurTextBBoxes() --------------------- */
1350
1351 static
UpdateStrBlockBBoxes(pStrBlock,x,baseline_y,clean)1352 void UpdateStrBlockBBoxes(pStrBlock, x, baseline_y, clean)
1353 StrBlockInfo *pStrBlock;
1354 int x, baseline_y, clean;
1355 {
1356 int saved_baseline_y=baseline_y;
1357 int block_w=pStrBlock->w;
1358
1359 SetBBRec((clean ? &pStrBlock->clean_bbox : &pStrBlock->bbox),
1360 x+textAbsMinLBearing, baseline_y-pStrBlock->asc,
1361 x+pStrBlock->w+textAbsMaxRExtra, baseline_y+pStrBlock->des);
1362 switch (pStrBlock->type) {
1363 case SB_SIMPLE: break;
1364 case SB_CHAR_SPACE: break;
1365
1366 case SB_SUPSUB_LEFT:
1367 case SB_SUPSUB_CENTER:
1368 case SB_SUPSUB_RIGHT:
1369 switch (pStrBlock->type) {
1370 case SB_SUPSUB_LEFT: x += block_w; break;
1371 case SB_SUPSUB_CENTER: x += (block_w>>1); break;
1372 case SB_SUPSUB_RIGHT: break;
1373 }
1374 if (pStrBlock->sup != NULL) {
1375 baseline_y = saved_baseline_y + pStrBlock->sup->baseline_offset;
1376 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1377 baseline_y -= pStrBlock->seg->asc;
1378 }
1379 UpdateMiniLinesBBoxes(pStrBlock->sup, x, baseline_y, clean);
1380 }
1381 if (pStrBlock->sub != NULL) {
1382 baseline_y = saved_baseline_y + pStrBlock->sub->baseline_offset;
1383 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1384 baseline_y += pStrBlock->seg->des;
1385 }
1386 UpdateMiniLinesBBoxes(pStrBlock->sub, x, baseline_y, clean);
1387 }
1388 break;
1389 }
1390 if (clean) {
1391 pStrBlock->clean = TRUE;
1392 memcpy(&pStrBlock->bbox, &pStrBlock->clean_bbox, sizeof(struct BBRec));
1393 } else if (!pStrBlock->clean ||
1394 CompareRect(&pStrBlock->clean_bbox, &pStrBlock->bbox) != 0) {
1395 pStrBlock->clean = FALSE;
1396 AddToDirtyBBox(&pStrBlock->clean_bbox);
1397 AddToDirtyBBox(&pStrBlock->bbox);
1398 }
1399 }
1400
1401 static
UpdateMiniLineBBoxes(pMiniLine,x,baseline_y,clean)1402 void UpdateMiniLineBBoxes(pMiniLine, x, baseline_y, clean)
1403 MiniLineInfo *pMiniLine;
1404 int x, baseline_y, clean;
1405 {
1406 int saved_x=x;
1407 StrBlockInfo *pStrBlock=NULL;
1408
1409 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
1410 pStrBlock=pStrBlock->next) {
1411 UpdateStrBlockBBoxes(pStrBlock, x, baseline_y, clean);
1412
1413 x += pStrBlock->w;
1414 }
1415 SetBBRec((clean ? &pMiniLine->clean_bbox : &pMiniLine->bbox),
1416 saved_x+textAbsMinLBearing, baseline_y-pMiniLine->asc,
1417 saved_x+pMiniLine->w+textAbsMaxRExtra, baseline_y+pMiniLine->des);
1418 if (clean) {
1419 pMiniLine->clean = TRUE;
1420 memcpy(&pMiniLine->bbox, &pMiniLine->clean_bbox, sizeof(struct BBRec));
1421 } else if (!pMiniLine->clean ||
1422 CompareRect(&pMiniLine->clean_bbox, &pMiniLine->bbox) != 0) {
1423 pMiniLine->clean = FALSE;
1424 AddToDirtyBBox(&pMiniLine->clean_bbox);
1425 AddToDirtyBBox(&pMiniLine->bbox);
1426 }
1427 }
1428
UpdateMiniLinesBBoxes(minilines,x,baseline_y,clean)1429 void UpdateMiniLinesBBoxes(minilines, x, baseline_y, clean)
1430 MiniLinesInfo *minilines;
1431 int x, baseline_y, clean;
1432 {
1433 MiniLineInfo *pMiniLine=NULL;
1434 int v_space=minilines->v_space;
1435 int saved_x=x, saved_baseline_y=baseline_y;
1436
1437 for (pMiniLine=minilines->first; pMiniLine != NULL;
1438 pMiniLine=pMiniLine->next) {
1439 baseline_y += pMiniLine->v_gap;
1440
1441 switch (minilines->just) {
1442 case JUST_L: x = saved_x; break;
1443 case JUST_C: x = saved_x - ((pMiniLine->w)>>1); break;
1444 case JUST_R: x = saved_x - pMiniLine->w; break;
1445 }
1446 UpdateMiniLineBBoxes(pMiniLine, x, baseline_y, clean);
1447
1448 baseline_y += pMiniLine->des + v_space;
1449 if (pMiniLine->next != NULL) {
1450 baseline_y += pMiniLine->next->asc;
1451 }
1452 }
1453 switch (minilines->just) {
1454 case JUST_L: x = saved_x; break;
1455 case JUST_C: x = saved_x - ((minilines->w)>>1); break;
1456 case JUST_R: x = saved_x - minilines->w; break;
1457 }
1458 SetBBRec((clean ? &minilines->clean_bbox : &minilines->bbox),
1459 x+textAbsMinLBearing, saved_baseline_y-minilines->first->asc,
1460 x+minilines->w+textAbsMaxRExtra,
1461 saved_baseline_y-minilines->first->asc+minilines->h);
1462 if (clean) {
1463 minilines->clean = TRUE;
1464 memcpy(&minilines->bbox, &minilines->clean_bbox, sizeof(struct BBRec));
1465 } else if (!minilines->clean ||
1466 CompareRect(&minilines->clean_bbox, &minilines->bbox) != 0) {
1467 minilines->clean = FALSE;
1468 AddToDirtyBBox(&minilines->clean_bbox);
1469 AddToDirtyBBox(&minilines->bbox);
1470 }
1471 }
1472
UpdateCurTextBBoxes(clean)1473 void UpdateCurTextBBoxes(clean)
1474 int clean;
1475 {
1476 struct TextRec *text_ptr=curTextObj->detail.t;
1477
1478 if (text_ptr->read_only) return;
1479
1480 UpdateMiniLinesBBoxes(&text_ptr->minilines, textOrigX, textOrigBaselineY,
1481 clean);
1482 }
1483
1484 /* --------------------- DoFuncOnStrSegForMiniLines() --------------------- */
1485
1486 static
DoFuncOnStrSegForStrSeg(pStrSeg,pFunc,pUserData)1487 void DoFuncOnStrSegForStrSeg(pStrSeg, pFunc, pUserData)
1488 StrSegInfo *pStrSeg;
1489 STRSEGFN *pFunc;
1490 void *pUserData;
1491 {
1492 (pFunc)(pStrSeg, pUserData);
1493 }
1494
1495 static
DoFuncOnStrSegForStrBlock(pStrBlock,pFunc,pUserData)1496 void DoFuncOnStrSegForStrBlock(pStrBlock, pFunc, pUserData)
1497 StrBlockInfo *pStrBlock;
1498 STRSEGFN *pFunc;
1499 void *pUserData;
1500 {
1501 switch (pStrBlock->type) {
1502 case SB_SIMPLE:
1503 DoFuncOnStrSegForStrSeg(pStrBlock->seg, pFunc, pUserData);
1504 break;
1505
1506 case SB_CHAR_SPACE: break;
1507
1508 case SB_SUPSUB_LEFT:
1509 case SB_SUPSUB_CENTER:
1510 case SB_SUPSUB_RIGHT:
1511 if (pStrBlock->sup != NULL) {
1512 DoFuncOnStrSegForMiniLines(pStrBlock->sup, pFunc, pUserData);
1513 }
1514 if (pStrBlock->sub != NULL) {
1515 DoFuncOnStrSegForMiniLines(pStrBlock->sub, pFunc, pUserData);
1516 }
1517 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1518 DoFuncOnStrSegForStrSeg(pStrBlock->seg, pFunc, pUserData);
1519 }
1520 break;
1521 }
1522 }
1523
1524 static
DoFuncOnStrSegForMiniLine(pMiniLine,pFunc,pUserData)1525 void DoFuncOnStrSegForMiniLine(pMiniLine, pFunc, pUserData)
1526 MiniLineInfo *pMiniLine;
1527 STRSEGFN *pFunc;
1528 void *pUserData;
1529 {
1530 StrBlockInfo *pStrBlock=NULL;
1531
1532 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
1533 pStrBlock=pStrBlock->next) {
1534 DoFuncOnStrSegForStrBlock(pStrBlock, pFunc, pUserData);
1535 }
1536 }
1537
DoFuncOnStrSegForMiniLines(minilines,pFunc,pUserData)1538 void DoFuncOnStrSegForMiniLines(minilines, pFunc, pUserData)
1539 MiniLinesInfo *minilines;
1540 STRSEGFN *pFunc;
1541 void *pUserData;
1542 {
1543 MiniLineInfo *pMiniLine=NULL;
1544
1545 for (pMiniLine=minilines->first; pMiniLine != NULL;
1546 pMiniLine=pMiniLine->next) {
1547 DoFuncOnStrSegForMiniLine(pMiniLine, pFunc, pUserData);
1548 }
1549 }
1550
1551 /* ===================== Text Routines ===================== */
1552
1553 /* --------------------- ResetOnCursorKey() --------------------- */
1554
ResetOnCursorKey(drag)1555 void ResetOnCursorKey(drag)
1556 int drag;
1557 {
1558 escPressed = FALSE;
1559 if (!drag) {
1560 endStrBlock = NULL;
1561 textEndIndex = INVALID;
1562 textHighlight = FALSE;
1563 }
1564 }
1565
1566 /* --------------------- PutTextCursor() --------------------- */
1567
PutTextCursor()1568 void PutTextCursor()
1569 {
1570 int asc=curStrBlock->seg->asc;
1571 int des=curStrBlock->seg->des;
1572
1573 if (!textHighlight) {
1574 if (drawWinHasFocus) {
1575 XDrawLine(mainDisplay, drawWindow, revDefaultGC, textCurX,
1576 textCurBaselineY-asc, textCurX, textCurBaselineY+des);
1577 }
1578 }
1579 if (canvasFontDoubleByte && gnInputMethod != TGIM_NONE && gnOverTheSpot) {
1580 if (!tgIMTellCursorPosition(mainDisplay, drawWindow, textCurX,
1581 textCurBaselineY+des)) {
1582 }
1583 }
1584 SetRightMarginActive();
1585 }
1586
1587 /* --------------------- EraseTextCursor() --------------------- */
1588
EraseTextCursor()1589 void EraseTextCursor()
1590 {
1591 int asc=curStrBlock->seg->asc;
1592 int des=curStrBlock->seg->des;
1593
1594 XDrawLine(mainDisplay, drawWindow, revDefaultGC, textCurX,
1595 textCurBaselineY-asc, textCurX, textCurBaselineY+des);
1596 }
1597
1598 /* --------------------- GetCurTextBBoxes() --------------------- */
1599
GetCurTextBBoxes(pOBBox,pBBox)1600 void GetCurTextBBoxes(pOBBox, pBBox)
1601 struct BBRec *pOBBox, *pBBox;
1602 /*
1603 * pOBBox bounds the inner curTextObj
1604 * pBBox bounds the outer curTextObj and textW and textH
1605 */
1606 {
1607 struct TextRec *text_ptr=curTextObj->detail.t;
1608 MiniLinesInfo *minilines=(&text_ptr->minilines);
1609 int ltx=0, lty=0, w=0, h=0;
1610
1611 if (pOBBox != NULL) {
1612 ltx = textOrigX;
1613 lty = textOrigBaselineY-minilines->first->asc;
1614 w = minilines->w;
1615 h = minilines->h;
1616 switch (minilines->just) {
1617 case JUST_L: break;
1618 case JUST_C: ltx -= (w>>1); break;
1619 case JUST_R: ltx -= w; break;
1620 }
1621 SetBBRec(pOBBox, ltx, lty, ltx+w, lty+h);
1622 }
1623 if (pBBox != NULL) {
1624 ltx = textOrigX;
1625 lty = textOrigY;
1626 w = textW;
1627 h = textH;
1628 switch (minilines->just) {
1629 case JUST_L: break;
1630 case JUST_C: ltx -= (w>>1); break;
1631 case JUST_R: ltx -= w; break;
1632 }
1633 SetBBRec(pBBox, ltx+textAbsMinLBearing, lty,
1634 ltx+w+textAbsMaxRExtra, lty+h);
1635 }
1636 }
1637
1638 /* --------------------- RedrawCurText() --------------------- */
1639
1640 static
UpdateTextHighlightInfo()1641 int UpdateTextHighlightInfo()
1642 {
1643 int min_y_1=0, max_y_1=0, min_y_2=0, max_y_2=0;
1644 int reverse=FALSE;
1645
1646 if (curStrBlock->depth != endStrBlock->depth) {
1647 #ifdef _TGIF_DBG /* debug, do not translate */
1648 fprintf(stderr, "curStrBlock->depth = %1d, endStrBlock->depth = %1d\n",
1649 curStrBlock->depth, endStrBlock->depth);
1650 #endif /* _TGIF_DBG */
1651 sprintf(gszMsgBox, TgLoadString(STID_UNEQUAL_DEPTHS_IN_FUNC),
1652 "UpdateTextHighlightInfo()");
1653 FatalUnexpectedError(gszMsgBox, NULL);
1654 return FALSE;
1655 }
1656 if (curStrBlock->type == SB_SUPSUB_CENTER) {
1657 min_y_1 = textCurBaselineY - curStrBlock->seg->asc;
1658 max_y_1 = textCurBaselineY + curStrBlock->seg->des;
1659 } else {
1660 min_y_1 = textCurBaselineY - curStrBlock->owner_mini_line->asc;
1661 max_y_1 = textCurBaselineY + curStrBlock->owner_mini_line->des;
1662 }
1663 if (endStrBlock->type == SB_SUPSUB_CENTER) {
1664 min_y_2 = textEndBaselineY - endStrBlock->seg->asc;
1665 max_y_2 = textEndBaselineY + endStrBlock->seg->des;
1666 } else {
1667 min_y_2 = textEndBaselineY - endStrBlock->owner_mini_line->asc;
1668 max_y_2 = textEndBaselineY + endStrBlock->owner_mini_line->des;
1669 }
1670
1671 if (curStrBlock->pre_order == endStrBlock->pre_order) {
1672 if (textCurX < textEndX) {
1673 reverse = FALSE;
1674 } else if (textCurX > textEndX) {
1675 reverse = TRUE;
1676 } else {
1677 textHighlight = FALSE;
1678 endStrBlock = NULL;
1679 textEndIndex = INVALID;
1680 return FALSE;
1681 }
1682 } else if (curStrBlock->pre_order < endStrBlock->pre_order) {
1683 reverse = FALSE;
1684 } else {
1685 reverse = TRUE;
1686 }
1687 if (reverse) {
1688 gstTextHighlightInfo.start_x = textEndX;
1689 gstTextHighlightInfo.start_min_y = min_y_2;
1690 gstTextHighlightInfo.start_max_y = max_y_2;
1691 gstTextHighlightInfo.start_baseline_y = textEndBaselineY;
1692
1693 gstTextHighlightInfo.end_x = textCurX;
1694 gstTextHighlightInfo.end_min_y = min_y_1;
1695 gstTextHighlightInfo.end_max_y = max_y_1;
1696 gstTextHighlightInfo.end_baseline_y = textCurBaselineY;
1697
1698 gstTextHighlightInfo.start_str_block_ptr = endStrBlock;
1699 gstTextHighlightInfo.start_index = textEndIndex;
1700 gstTextHighlightInfo.end_str_block_ptr = curStrBlock;
1701 gstTextHighlightInfo.end_index = textCurIndex;
1702 } else {
1703 gstTextHighlightInfo.start_x = textCurX;
1704 gstTextHighlightInfo.start_min_y = min_y_1;
1705 gstTextHighlightInfo.start_max_y = max_y_1;
1706 gstTextHighlightInfo.start_baseline_y = textCurBaselineY;
1707
1708 gstTextHighlightInfo.end_x = textEndX;
1709 gstTextHighlightInfo.end_min_y = min_y_2;
1710 gstTextHighlightInfo.end_max_y = max_y_2;
1711 gstTextHighlightInfo.end_baseline_y = textEndBaselineY;
1712
1713 gstTextHighlightInfo.start_str_block_ptr = curStrBlock;
1714 gstTextHighlightInfo.start_index = textCurIndex;
1715 gstTextHighlightInfo.end_str_block_ptr = endStrBlock;
1716 gstTextHighlightInfo.end_index = textEndIndex;
1717 }
1718 return TRUE;
1719 }
1720
1721 static
GetMinilineHomeXY(pMiniLine,pn_x,pn_baseline_y)1722 void GetMinilineHomeXY(pMiniLine, pn_x, pn_baseline_y)
1723 MiniLineInfo *pMiniLine;
1724 int *pn_x, *pn_baseline_y;
1725 {
1726 #ifdef _TGIF_DBG /* debug, do not translate */
1727 TgAssert(pMiniLine->first_block->type == SB_SIMPLE ||
1728 pMiniLine->first_block->type == SB_SUPSUB_CENTER,
1729 "First StrBlock has invalid type in GetMinilineHomeXY()",
1730 NULL);
1731 #endif /* _TGIF_DBG */
1732 GetTextXY(pMiniLine->first_block, 0, pn_x, pn_baseline_y);
1733 }
1734
1735 static
GetMinilineEndXY(pMiniLine,pn_x,pn_baseline_y)1736 void GetMinilineEndXY(pMiniLine, pn_x, pn_baseline_y)
1737 MiniLineInfo *pMiniLine;
1738 int *pn_x, *pn_baseline_y;
1739 {
1740 StrBlockInfo *pStrBlock=NULL;
1741 int index=INVALID;
1742
1743 for (pStrBlock=pMiniLine->first_block; pStrBlock->next != NULL;
1744 pStrBlock=pStrBlock->next) {
1745 }
1746 switch (pStrBlock->type) {
1747 case SB_SIMPLE:
1748 case SB_SUPSUB_CENTER:
1749 index = pStrBlock->seg->dyn_str.sz-1;
1750 break;
1751 case SB_CHAR_SPACE:
1752 #ifdef _TGIF_DBG /* debug, do not translate */
1753 TgAssert(FALSE,
1754 "Last StrBlock has type of SB_CHAR_SPACE in GetMinilineEndXY()",
1755 NULL);
1756 #endif /* _TGIF_DBG */
1757 index = 1;
1758 break;
1759 }
1760 GetTextXY(pStrBlock, index, pn_x, pn_baseline_y);
1761 }
1762
1763 static
PaintTextHighlight()1764 void PaintTextHighlight()
1765 {
1766 XGCValues values;
1767
1768 if (!UpdateTextHighlightInfo()) return;
1769
1770 if (useAltEditTextBgColor) {
1771 if (altEditTextHighlightIndex == INVALID) {
1772 values.foreground = myBgPixel;
1773 } else {
1774 values.foreground = colorPixels[altEditTextHighlightIndex];
1775 }
1776 } else {
1777 values.foreground = myFgPixel;
1778 }
1779 values.function = GXcopy;
1780 values.fill_style = FillSolid;
1781 XChangeGC(mainDisplay, drawGC, GCForeground | GCFunction | GCFillStyle,
1782 &values);
1783 if (gstTextHighlightInfo.start_min_y == gstTextHighlightInfo.end_min_y) {
1784 int w=(gstTextHighlightInfo.end_x-gstTextHighlightInfo.start_x);
1785 int h=(gstTextHighlightInfo.start_max_y-gstTextHighlightInfo.start_min_y);
1786
1787 XFillRectangle(mainDisplay, drawWindow, drawGC,
1788 gstTextHighlightInfo.start_x, gstTextHighlightInfo.start_min_y,
1789 w, h);
1790 } else {
1791 int start_x=0, end_x=0, min_y=0, max_y=0;
1792 MiniLineInfo *pMiniLine=NULL;
1793 MiniLineInfo *pStartMiniLine=
1794 gstTextHighlightInfo.start_str_block_ptr->owner_mini_line;
1795 MiniLineInfo *pEndMiniLine=
1796 gstTextHighlightInfo.end_str_block_ptr->owner_mini_line;
1797
1798 start_x = gstTextHighlightInfo.start_x;
1799 GetMinilineEndXY(pStartMiniLine, &end_x, NULL);
1800 min_y = gstTextHighlightInfo.start_min_y;
1801 max_y = gstTextHighlightInfo.start_max_y;
1802 XFillRectangle(mainDisplay, drawWindow, drawGC,
1803 start_x, min_y, end_x-start_x, max_y-min_y);
1804 for (pMiniLine=pStartMiniLine->next; pMiniLine != pEndMiniLine;
1805 pMiniLine=pMiniLine->next) {
1806 int left_baseline_y=0, right_baseline_y=0;
1807
1808 GetMinilineHomeXY(pMiniLine, &start_x, &left_baseline_y);
1809 GetMinilineEndXY(pMiniLine, &end_x, &right_baseline_y);
1810 if (left_baseline_y != right_baseline_y) {
1811 sprintf(gszMsgBox, TgLoadString(STID_BASELINE_YS_NOT_EQ_IN_FUNC),
1812 "PaintTextHighlight()");
1813 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1814 }
1815 min_y = left_baseline_y - pMiniLine->asc;
1816 max_y = left_baseline_y + pMiniLine->des;
1817 XFillRectangle(mainDisplay, drawWindow, drawGC,
1818 start_x, min_y, end_x-start_x, max_y-min_y);
1819 }
1820 GetMinilineHomeXY(pMiniLine, &start_x, NULL);
1821 end_x = gstTextHighlightInfo.end_x;
1822 min_y = gstTextHighlightInfo.end_min_y;
1823 max_y = gstTextHighlightInfo.end_max_y;
1824 XFillRectangle(mainDisplay, drawWindow, drawGC,
1825 start_x, min_y, end_x-start_x, max_y-min_y);
1826 }
1827 }
1828
1829 static
GetPaintMode(pStrBlock,pnMode,pnFirstIndex,pnSecondIndex)1830 void GetPaintMode(pStrBlock, pnMode, pnFirstIndex, pnSecondIndex)
1831 int *pnMode, *pnFirstIndex, *pnSecondIndex;
1832 StrBlockInfo *pStrBlock;
1833 {
1834 *pnMode = gstTextHighlightInfo.mode;
1835 *pnFirstIndex = INVALID;
1836 *pnSecondIndex = INVALID;
1837
1838 if (gstTextHighlightInfo.highlighting) {
1839 if (pStrBlock == gstTextHighlightInfo.end_str_block_ptr) {
1840 if (pStrBlock == gstTextHighlightInfo.end_str_block_ptr) {
1841 *pnMode = PAINT_INV_NORM;
1842 *pnFirstIndex = gstTextHighlightInfo.end_index;
1843 } else {
1844 *pnMode = PAINT_INV;
1845 }
1846 }
1847 } else {
1848 if (pStrBlock == gstTextHighlightInfo.start_str_block_ptr) {
1849 if (pStrBlock == gstTextHighlightInfo.end_str_block_ptr) {
1850 *pnMode = PAINT_NORM_INV_NORM;
1851 *pnFirstIndex = gstTextHighlightInfo.start_index;
1852 *pnSecondIndex = gstTextHighlightInfo.end_index;
1853 } else {
1854 *pnMode = PAINT_NORM_INV;
1855 *pnFirstIndex = gstTextHighlightInfo.start_index;
1856 gstTextHighlightInfo.highlighting = TRUE;
1857 }
1858 }
1859 }
1860 gstTextHighlightInfo.mode = (*pnMode);
1861 }
1862
1863 static
PaintString(dpy,d,gc,depth,x,baseline_y,buf,len,color_pixel,underline_on,overline_on,mode,first_index,second_index)1864 void PaintString(dpy, d, gc, depth, x, baseline_y, buf, len, color_pixel,
1865 underline_on, overline_on, mode, first_index, second_index)
1866 Display *dpy;
1867 Drawable d;
1868 GC gc;
1869 int depth, x, baseline_y, len, color_pixel, underline_on, overline_on;
1870 int mode, first_index, second_index;
1871 char *buf;
1872 /*
1873 * x is the left edge of the string.
1874 */
1875 {
1876 int inv_pixel=myBgPixel, w=0;
1877 int underline_yoffset=curUnderlineYOffset;
1878 int overline_yoffset=curOverlineYOffset;
1879 int overunder=(underline_on || overline_on);
1880
1881 if (useAltEditTextBgColor) {
1882 if (altEditTextBgIndex == INVALID) {
1883 inv_pixel = myFgPixel;
1884 } else {
1885 inv_pixel = colorPixels[altEditTextBgIndex];
1886 }
1887 } else {
1888 inv_pixel = myBgPixel;
1889 }
1890 if (mode & PAINT) {
1891 switch (mode) {
1892 case PAINT_NORM:
1893 XSetForeground(dpy, gc, color_pixel);
1894 MyDrawString(dpy, d, gc, depth, x, baseline_y, buf, len);
1895 if (overunder) {
1896 w = MyTextWidth(canvasFontPtr, buf, len);
1897 if (underline_on) {
1898 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1899 x+w, baseline_y+underline_yoffset);
1900 }
1901 if (overline_on) {
1902 XDrawLine(dpy, d, gc,
1903 x, baseline_y-canvasFontAsc-overline_yoffset,
1904 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1905 }
1906 }
1907 break;
1908 case PAINT_INV:
1909 XSetForeground(dpy, gc, inv_pixel);
1910 MyDrawString(dpy, d, gc, depth, x, baseline_y, buf, len);
1911 if (overunder) {
1912 w = MyTextWidth(canvasFontPtr, buf, len);
1913 if (underline_on) {
1914 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1915 x+w, baseline_y+underline_yoffset);
1916 }
1917 if (overline_on) {
1918 XDrawLine(dpy, d, gc,
1919 x, baseline_y-canvasFontAsc-overline_yoffset,
1920 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1921 }
1922 }
1923 break;
1924 case PAINT_NORM_INV:
1925 XSetForeground(dpy, gc, color_pixel);
1926 MyDrawString(dpy, d, gc, depth, x, baseline_y, buf, first_index);
1927 w = MyTextWidth(canvasFontPtr, buf, first_index);
1928 if (underline_on) {
1929 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1930 x+w, baseline_y+underline_yoffset);
1931 }
1932 if (overline_on) {
1933 XDrawLine(dpy, d, gc, x, baseline_y-canvasFontAsc-overline_yoffset,
1934 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1935 }
1936 x += w;
1937 XSetForeground(dpy, gc, inv_pixel);
1938 MyDrawString(dpy, d, gc, depth, x, baseline_y, &buf[first_index],
1939 len-first_index);
1940 if (overunder) {
1941 w = MyTextWidth(canvasFontPtr, &buf[first_index], len-first_index);
1942 if (underline_on) {
1943 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1944 x+w, baseline_y+underline_yoffset);
1945 }
1946 if (overline_on) {
1947 XDrawLine(dpy, d, gc,
1948 x, baseline_y-canvasFontAsc-overline_yoffset,
1949 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1950 }
1951 }
1952 break;
1953 case PAINT_INV_NORM:
1954 XSetForeground(dpy, gc, inv_pixel);
1955 MyDrawString(dpy, d, gc, depth, x, baseline_y, buf, first_index);
1956 w = MyTextWidth(canvasFontPtr, buf, first_index);
1957 if (underline_on) {
1958 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1959 x+w, baseline_y+underline_yoffset);
1960 }
1961 if (overline_on) {
1962 XDrawLine(dpy, d, gc, x, baseline_y-canvasFontAsc-overline_yoffset,
1963 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1964 }
1965 x += w;
1966 XSetForeground(dpy, gc, color_pixel);
1967 MyDrawString(dpy, d, gc, depth, x, baseline_y, &buf[first_index],
1968 len-first_index);
1969 if (overunder) {
1970 w = MyTextWidth(canvasFontPtr, &buf[first_index], len-first_index);
1971 if (underline_on) {
1972 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1973 x+w, baseline_y+underline_yoffset);
1974 }
1975 if (overline_on) {
1976 XDrawLine(dpy, d, gc,
1977 x, baseline_y-canvasFontAsc-overline_yoffset,
1978 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1979 }
1980 }
1981 break;
1982 case PAINT_NORM_INV_NORM:
1983 XSetForeground(dpy, gc, color_pixel);
1984 MyDrawString(dpy, d, gc, depth, x, baseline_y, buf, first_index);
1985 w = MyTextWidth(canvasFontPtr, buf, first_index);
1986 if (underline_on) {
1987 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
1988 x+w, baseline_y+underline_yoffset);
1989 }
1990 if (overline_on) {
1991 XDrawLine(dpy, d, gc, x, baseline_y-canvasFontAsc-overline_yoffset,
1992 x+w, baseline_y-canvasFontAsc-overline_yoffset);
1993 }
1994 x += w;
1995 XSetForeground(dpy, gc, inv_pixel);
1996 MyDrawString(dpy, d, gc, depth, x, baseline_y, &buf[first_index],
1997 second_index-first_index);
1998 w = MyTextWidth(canvasFontPtr, &buf[first_index],
1999 second_index-first_index);
2000 if (underline_on) {
2001 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
2002 x+w, baseline_y+underline_yoffset);
2003 }
2004 if (overline_on) {
2005 XDrawLine(dpy, d, gc, x, baseline_y-canvasFontAsc-overline_yoffset,
2006 x+w, baseline_y-canvasFontAsc-overline_yoffset);
2007 }
2008 x += w;
2009 XSetForeground(dpy, gc, color_pixel);
2010 MyDrawString(dpy, d, gc, depth, x, baseline_y, &buf[second_index],
2011 len-second_index);
2012 if (overunder) {
2013 w = MyTextWidth(canvasFontPtr, &buf[second_index],
2014 len-second_index);
2015 if (underline_on) {
2016 XDrawLine(dpy, d, gc, x, baseline_y+underline_yoffset,
2017 x+w, baseline_y+underline_yoffset);
2018 }
2019 if (overline_on) {
2020 XDrawLine(dpy, d, gc,
2021 x, baseline_y-canvasFontAsc-overline_yoffset,
2022 x+w, baseline_y-canvasFontAsc-overline_yoffset);
2023 }
2024 }
2025 break;
2026 }
2027 }
2028 }
2029
2030 static
PaintStrSeg(dpy,d,gc,depth,x,baseline_y,pStrSeg,use_highlight,use_as_mask,mode,first_index,second_index)2031 void PaintStrSeg(dpy, d, gc, depth, x, baseline_y, pStrSeg, use_highlight,
2032 use_as_mask, mode, first_index, second_index)
2033 Display *dpy;
2034 Drawable d;
2035 GC gc;
2036 int depth, x, baseline_y, use_highlight, use_as_mask;
2037 int mode, first_index, second_index;
2038 StrSegInfo *pStrSeg;
2039 /*
2040 * x is the left edge of the string segment.
2041 */
2042 {
2043 XGCValues values;
2044
2045 curFont = pStrSeg->font;
2046 curStyle = pStrSeg->style;
2047 curSzUnit = pStrSeg->sz_unit;
2048
2049 SetCanvasFont();
2050
2051 if (use_as_mask) {
2052 values.foreground = 1;
2053 } else if (colorDisplay) {
2054 values.foreground = colorPixels[pStrSeg->color];
2055 } else {
2056 values.foreground = myFgPixel;
2057 }
2058 values.function = GXcopy;
2059 values.fill_style = (transPat ? FillStippled : FillOpaqueStippled);
2060 values.stipple = patPixmap[penPat];
2061 values.font = canvasFontPtr->fid;
2062 values.line_width = 1;
2063 values.line_style = LineSolid;
2064 XChangeGC(dpy, gc, GCForeground | GCFunction | GCFillStyle | GCStipple |
2065 GCFont | GCLineWidth | GCLineStyle, &values);
2066
2067 if (use_highlight && !use_as_mask) {
2068 PaintString(dpy, d, gc, depth, x, baseline_y, pStrSeg->dyn_str.s,
2069 pStrSeg->dyn_str.sz-1,
2070 (colorDisplay ? colorPixels[pStrSeg->color] : myFgPixel),
2071 pStrSeg->underline_on, pStrSeg->overline_on, mode, first_index,
2072 second_index);
2073 switch (mode) {
2074 case PAINT_NORM:
2075 case PAINT_INV_NORM:
2076 case PAINT_NORM_INV_NORM:
2077 gstTextHighlightInfo.mode = PAINT_NORM;
2078 break;
2079 case PAINT_INV:
2080 case PAINT_NORM_INV:
2081 gstTextHighlightInfo.mode = PAINT_INV;
2082 break;
2083 }
2084 } else {
2085 MyDrawString(dpy, d, gc, depth, x, baseline_y, pStrSeg->dyn_str.s,
2086 pStrSeg->dyn_str.sz-1);
2087 if (pStrSeg->underline_on) {
2088 int offset=curUnderlineYOffset;
2089
2090 XDrawLine(dpy, d, gc, x, baseline_y+offset, x+pStrSeg->w,
2091 baseline_y+offset);
2092 }
2093 if (pStrSeg->overline_on) {
2094 int offset=curOverlineYOffset;
2095
2096 XDrawLine(dpy, d, gc, x, baseline_y-canvasFontAsc-offset, x+pStrSeg->w,
2097 baseline_y-canvasFontAsc-offset);
2098 }
2099 }
2100 }
2101
2102 static
PaintStrBlock(dpy,d,gc,depth,x,baseline_y,pStrBlock,use_highlight,use_as_mask)2103 void PaintStrBlock(dpy, d, gc, depth, x, baseline_y, pStrBlock, use_highlight,
2104 use_as_mask)
2105 Display *dpy;
2106 Drawable d;
2107 GC gc;
2108 int depth, x, baseline_y, use_highlight, use_as_mask;
2109 StrBlockInfo *pStrBlock;
2110 /*
2111 * x is the left edge of the string block.
2112 */
2113 {
2114 int saved_baseline_y=baseline_y;
2115 int block_w=pStrBlock->w;
2116 int mode=INVALID, first_index=INVALID, second_index=INVALID;
2117
2118 if (GetDirtyBBox(NULL) && !IntersectDirtyBBox(&pStrBlock->bbox)) {
2119 return;
2120 }
2121 if (use_highlight && !use_as_mask) {
2122 switch (pStrBlock->type) {
2123 case SB_SIMPLE:
2124 case SB_CHAR_SPACE:
2125 case SB_SUPSUB_CENTER:
2126 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
2127 break;
2128 }
2129 }
2130 switch (pStrBlock->type) {
2131 case SB_SIMPLE:
2132 PaintStrSeg(dpy, d, gc, depth, x, baseline_y, pStrBlock->seg,
2133 use_highlight, use_as_mask, mode, first_index, second_index);
2134 break;
2135
2136 case SB_CHAR_SPACE: break;
2137
2138 case SB_SUPSUB_LEFT:
2139 case SB_SUPSUB_CENTER:
2140 case SB_SUPSUB_RIGHT:
2141 switch (pStrBlock->type) {
2142 case SB_SUPSUB_LEFT: x += block_w; break;
2143 case SB_SUPSUB_CENTER: x += (block_w>>1); break;
2144 case SB_SUPSUB_RIGHT: break;
2145 }
2146 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2147 /* pStrBlock->seg better not be NULL or it will crash */
2148 baseline_y = saved_baseline_y;
2149 PaintStrSeg(dpy, d, gc, depth, x-((pStrBlock->seg->w)>>1), baseline_y,
2150 pStrBlock->seg, use_highlight, use_as_mask, mode, first_index,
2151 second_index);
2152 }
2153 if (pStrBlock->sup != NULL) {
2154 baseline_y = saved_baseline_y + pStrBlock->sup->baseline_offset;
2155 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2156 baseline_y -= pStrBlock->seg->asc;
2157 }
2158 PaintMiniLines(dpy, d, gc, depth, x, baseline_y, pStrBlock->sup,
2159 use_highlight, use_as_mask);
2160 }
2161 if (pStrBlock->sub != NULL) {
2162 baseline_y = saved_baseline_y + pStrBlock->sub->baseline_offset;
2163 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2164 baseline_y += pStrBlock->seg->des;
2165 }
2166 PaintMiniLines(dpy, d, gc, depth, x, baseline_y, pStrBlock->sub,
2167 use_highlight, use_as_mask);
2168 }
2169 break;
2170 }
2171 }
2172
2173 static
PaintMiniLine(dpy,d,gc,depth,x,baseline_y,pMiniLine,use_highlight,use_as_mask)2174 void PaintMiniLine(dpy, d, gc, depth, x, baseline_y, pMiniLine, use_highlight,
2175 use_as_mask)
2176 Display *dpy;
2177 Drawable d;
2178 GC gc;
2179 int depth, x, baseline_y, use_highlight, use_as_mask;
2180 MiniLineInfo *pMiniLine;
2181 /*
2182 * x is the left edge of the miniline and baseline_y has been adjusted by
2183 * pMiniLine->v_gap.
2184 */
2185 {
2186 StrBlockInfo *pStrBlock=NULL;
2187
2188 if (GetDirtyBBox(NULL) && !IntersectDirtyBBox(&pMiniLine->bbox)) {
2189 return;
2190 }
2191 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
2192 pStrBlock=pStrBlock->next) {
2193 PaintStrBlock(dpy, d, gc, depth, x, baseline_y, pStrBlock, use_highlight,
2194 use_as_mask);
2195
2196 x += pStrBlock->w;
2197 }
2198 }
2199
PaintMiniLines(dpy,d,gc,depth,x,baseline_y,minilines,use_highlight,use_as_mask)2200 void PaintMiniLines(dpy, d, gc, depth, x, baseline_y, minilines, use_highlight,
2201 use_as_mask)
2202 Display *dpy;
2203 Drawable d;
2204 GC gc;
2205 int depth, x, baseline_y, use_highlight, use_as_mask;
2206 MiniLinesInfo *minilines;
2207 /*
2208 * x is the origin of the minilines (not the left edge)
2209 */
2210 {
2211 MiniLineInfo *pMiniLine=NULL;
2212 int v_space=minilines->v_space;
2213 int saved_x=x;
2214
2215 if (GetDirtyBBox(NULL) && !IntersectDirtyBBox(&minilines->bbox)) {
2216 return;
2217 }
2218 for (pMiniLine=minilines->first; pMiniLine != NULL;
2219 pMiniLine=pMiniLine->next) {
2220 #ifdef _TGIF_DBG /* debug, do not translate */
2221 if (pMiniLine == minilines->first) {
2222 TgAssert(pMiniLine->v_gap == 0,
2223 "First mini_line has non-zero v_gap in PaintMiniLines()",
2224 NULL);
2225 }
2226 #endif /* _TGIF_DBG */
2227 baseline_y += pMiniLine->v_gap;
2228
2229 switch (minilines->just) {
2230 case JUST_L: x = saved_x; break;
2231 case JUST_C: x = saved_x - ((pMiniLine->w)>>1); break;
2232 case JUST_R: x = saved_x - pMiniLine->w; break;
2233 }
2234 PaintMiniLine(dpy, d, gc, depth, x, baseline_y, pMiniLine, use_highlight,
2235 use_as_mask);
2236
2237 baseline_y += pMiniLine->des + v_space;
2238 if (pMiniLine->next != NULL) {
2239 baseline_y += pMiniLine->next->asc;
2240 }
2241 }
2242 }
2243
2244 static
PaintCurText()2245 void PaintCurText()
2246 {
2247 struct TextRec *text_ptr=curTextObj->detail.t;
2248 MiniLinesInfo *minilines=(&text_ptr->minilines);
2249 int baseline_y=textOrigBaselineY, saved_pen=penPat;
2250
2251 PushCurFont();
2252
2253 memset(&gstTextHighlightInfo, 0, sizeof(TextHighlightInfo));
2254 if (textHighlight) {
2255 PaintTextHighlight();
2256 }
2257 gstTextHighlightInfo.highlighting = FALSE;
2258 gstTextHighlightInfo.mode = PAINT_NORM;
2259
2260 curUnderlineYOffset = text_ptr->underline_y_offset;
2261 curOverlineYOffset = text_ptr->overline_y_offset;
2262 penPat = SOLIDPAT;
2263 PaintMiniLines(mainDisplay, drawWindow, drawGC, mainDepth,
2264 textOrigX, baseline_y, minilines, TRUE, FALSE);
2265 penPat = saved_pen;
2266
2267 PopCurFont();
2268 }
2269
DrawCurTextOutLine(x,y,w,h)2270 void DrawCurTextOutLine(x, y, w, h)
2271 int x, y, w, h;
2272 {
2273 XGCValues values;
2274
2275 values.foreground = myFgPixel;
2276 values.function = GXcopy;
2277 values.fill_style = FillOpaqueStippled;
2278 values.stipple = patPixmap[SCROLLPAT];
2279 values.line_width = curTextOutlineW;
2280 values.line_style = LineSolid;
2281 values.join_style = JoinMiter;
2282 XChangeGC(mainDisplay, drawGC,
2283 GCForeground | GCFunction | GCFillStyle | GCStipple | GCLineWidth |
2284 GCLineStyle | GCJoinStyle, &values);
2285
2286 XDrawRectangle(mainDisplay, drawWindow, drawGC,
2287 x-curTextOutlineHalfW, y-curTextOutlineHalfW,
2288 w+(curTextOutlineHalfW<<1), h+(curTextOutlineHalfW<<1));
2289 }
2290
RedrawCurText()2291 void RedrawCurText()
2292 {
2293 int x=0, y=0, w=0, h=0, clipped=FALSE;
2294 XGCValues values;
2295
2296 if (curChoice != DRAWTEXT || !textCursorShown) return;
2297
2298 if (GetDirtyBBox(NULL)) {
2299 struct BBRec draw_win_bbox;
2300
2301 draw_win_bbox.ltx = draw_win_bbox.lty = 0;
2302 draw_win_bbox.rbx = initDrawWinW;
2303 draw_win_bbox.rby = initDrawWinH;
2304 if (!IntersectRect(gstDirtyBBoxInfo.bbox, draw_win_bbox,
2305 &gstDirtyBBoxInfo.bbox)) {
2306 return;
2307 }
2308 SetRecVals(clipRecs[0], gstDirtyBBoxInfo.bbox.ltx,
2309 gstDirtyBBoxInfo.bbox.lty,
2310 gstDirtyBBoxInfo.bbox.rbx-gstDirtyBBoxInfo.bbox.ltx+1,
2311 gstDirtyBBoxInfo.bbox.rby-gstDirtyBBoxInfo.bbox.lty+1);
2312 numClipRecs = 1;
2313 clipOrdering = YXBanded;
2314 XSetClipRectangles(mainDisplay, drawGC, 0, 0, clipRecs, numClipRecs,
2315 clipOrdering);
2316 clipped = TRUE;
2317 }
2318 GetCurTextBBoxes(NULL, &curTextBBox);
2319 x = curTextBBox.ltx-2;
2320 y = curTextBBox.lty-2;
2321 w = curTextBBox.rbx-curTextBBox.ltx+4;
2322 h = curTextBBox.rby-curTextBBox.lty+4;
2323
2324 if (useAltEditTextBgColor) {
2325 if (altEditTextBgIndex == INVALID) {
2326 values.foreground = myFgPixel;
2327 } else {
2328 values.foreground = colorPixels[altEditTextBgIndex];
2329 }
2330 } else {
2331 values.foreground = GetDrawingBgPixel(INVALID, INVALID);
2332 }
2333 values.function = GXcopy;
2334 values.fill_style = FillSolid;
2335 values.line_width = 1;
2336 values.line_style = LineSolid;
2337 XChangeGC(mainDisplay, drawGC,
2338 GCForeground | GCFunction | GCFillStyle | GCLineWidth | GCLineStyle,
2339 &values);
2340 XFillRectangle(mainDisplay, drawWindow, drawGC, x, y, w, h);
2341 DrawCurTextOutLine(x, y, w, h);
2342
2343 PaintCurText();
2344 if (clipped) {
2345 SetDefaultDrawWinClipRecs();
2346 }
2347 PutTextCursor();
2348 ResetDirtyBBoxInfo();
2349 UpdateCurTextBBoxes(TRUE);
2350 }
2351
2352 /* --------------------- UpdateHighLightedTextBBoxes() --------------------- */
2353
UpdateHighLightedTextBBoxes(clean)2354 void UpdateHighLightedTextBBoxes(clean)
2355 int clean;
2356 {
2357 if (clean) {
2358 ResetDirtyBBoxInfo();
2359 } else {
2360 UpdateCurTextBBoxes(FALSE);
2361 }
2362 AddToDirtyBBox(&curStrBlock->clean_bbox);
2363
2364 if (textHighlight && UpdateTextHighlightInfo()) {
2365 int w=(gstTextHighlightInfo.end_x-gstTextHighlightInfo.start_x);
2366 int h=(gstTextHighlightInfo.start_max_y-gstTextHighlightInfo.start_min_y);
2367 struct BBRec bbox;
2368
2369 SetBBRec(&bbox, gstTextHighlightInfo.start_x,
2370 gstTextHighlightInfo.start_min_y, gstTextHighlightInfo.start_x+w,
2371 gstTextHighlightInfo.start_min_y+h);
2372 AddToDirtyBBox(&endStrBlock->clean_bbox);
2373 AddToDirtyBBox(&bbox);
2374
2375 if (gstTextHighlightInfo.start_min_y != gstTextHighlightInfo.end_min_y) {
2376 int start_x=0, end_x=0, min_y=0, max_y=0;
2377 MiniLineInfo *pMiniLine=NULL;
2378 MiniLineInfo *pStartMiniLine=
2379 gstTextHighlightInfo.start_str_block_ptr->owner_mini_line;
2380 MiniLineInfo *pEndMiniLine=
2381 gstTextHighlightInfo.end_str_block_ptr->owner_mini_line;
2382
2383 AddToDirtyBBox(&endStrBlock->clean_bbox);
2384
2385 start_x = gstTextHighlightInfo.start_x;
2386 GetMinilineEndXY(pStartMiniLine, &end_x, NULL);
2387 min_y = gstTextHighlightInfo.start_min_y;
2388 max_y = gstTextHighlightInfo.start_max_y;
2389 SetBBRec(&bbox, start_x, min_y, end_x, max_y);
2390 AddToDirtyBBox(&bbox);
2391 for (pMiniLine=pStartMiniLine->next; pMiniLine != pEndMiniLine;
2392 pMiniLine=pMiniLine->next) {
2393 int left_baseline_y=0, right_baseline_y=0;
2394
2395 GetMinilineHomeXY(pMiniLine, &start_x, &left_baseline_y);
2396 GetMinilineEndXY(pMiniLine, &end_x, &right_baseline_y);
2397 if (left_baseline_y != right_baseline_y) {
2398 sprintf(gszMsgBox, TgLoadString(STID_BASELINE_YS_NOT_EQ_IN_FUNC),
2399 "PaintTextHighlight()");
2400 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2401 }
2402 min_y = left_baseline_y - pMiniLine->asc;
2403 max_y = left_baseline_y + pMiniLine->des;
2404 SetBBRec(&bbox, start_x, min_y, end_x, max_y);
2405 AddToDirtyBBox(&bbox);
2406 }
2407 GetMinilineHomeXY(pMiniLine, &start_x, NULL);
2408 end_x = gstTextHighlightInfo.end_x;
2409 min_y = gstTextHighlightInfo.end_min_y;
2410 max_y = gstTextHighlightInfo.end_max_y;
2411 SetBBRec(&bbox, start_x, min_y, end_x, max_y);
2412 AddToDirtyBBox(&bbox);
2413 }
2414 }
2415 }
2416
2417 /* --------------------- DeleteHighlightedText() --------------------- */
2418
2419 static
DeleteHighlightedTextInStrSeg(pStrSeg,mode,first_index,second_index)2420 int DeleteHighlightedTextInStrSeg(pStrSeg, mode, first_index, second_index)
2421 StrSegInfo *pStrSeg;
2422 int mode, first_index, second_index;
2423 /* return TRUE if all done deleting */
2424 {
2425 char *psz=NULL, *psz1=NULL, *psz2=NULL;
2426
2427 switch (mode) {
2428 case PAINT_NORM: break;
2429 case PAINT_INV: break;
2430
2431 case PAINT_NORM_INV:
2432 /* delete the tail */
2433 pStrSeg->dyn_str.s[first_index] = '\0';
2434 if ((psz=UtilStrDup(pStrSeg->dyn_str.s)) == NULL) FailAllocMessage();
2435 DynStrSet(&pStrSeg->dyn_str, psz);
2436 UtilFree(psz);
2437 gstTextHighlightInfo.mode = PAINT_INV;
2438 break;
2439
2440 case PAINT_INV_NORM:
2441 if ((psz=UtilStrDup(&pStrSeg->dyn_str.s[first_index])) == NULL) {
2442 FailAllocMessage();
2443 }
2444 DynStrSet(&pStrSeg->dyn_str, psz);
2445 UtilFree(psz);
2446 gstTextHighlightInfo.mode = PAINT_NORM;
2447 return TRUE;
2448
2449 case PAINT_NORM_INV_NORM:
2450 if ((psz=UtilStrDup(pStrSeg->dyn_str.s)) == NULL) {
2451 FailAllocMessage();
2452 }
2453 for (psz1=(&psz[first_index]), psz2=(&psz[second_index]);
2454 *psz2 != '\0'; psz1++, psz2++) {
2455 *psz1 = *psz2;
2456 }
2457 *psz1 = '\0';
2458 DynStrSet(&pStrSeg->dyn_str, psz);
2459 UtilFree(psz);
2460 gstTextHighlightInfo.mode = PAINT_NORM;
2461 return TRUE;
2462 }
2463 return FALSE;
2464 }
2465
MergeNextMiniLineWhileDeleting(pMiniLine)2466 void MergeNextMiniLineWhileDeleting(pMiniLine)
2467 MiniLineInfo *pMiniLine;
2468 /* combine pMiniLine and pMiniLine->next */
2469 {
2470 StrBlockInfo *pStrBlock=NULL;
2471 MiniLineInfo *pMiniLineToFree=pMiniLine->next;
2472
2473 #ifdef _TGIF_DBG /* debug, do not translate */
2474 if (pMiniLine->next == NULL) {
2475 sprintf(gszMsgBox, "%s: %s %s.",
2476 "Failed assertion", "pMiniLine->next == NULL in",
2477 "MergeNextMiniLineWhileDeleting()");
2478 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2479 }
2480 #endif /* _TGIF_DBG */
2481 for (pStrBlock=pMiniLineToFree->first_block; pStrBlock != NULL;
2482 pStrBlock=pStrBlock->next) {
2483 pStrBlock->owner_mini_line = pMiniLine;
2484 }
2485 pMiniLine->last_block->next = pMiniLineToFree->first_block;
2486 pMiniLineToFree->first_block->prev = pMiniLine->last_block;
2487 pMiniLine->last_block = pMiniLineToFree->last_block;
2488 UnlinkMiniLine(pMiniLineToFree);
2489 pMiniLineToFree->first_block = pMiniLineToFree->last_block = NULL;
2490 FreeMiniLine(pMiniLineToFree);
2491 }
2492
StrBlocksHasSameProperties(pStrBlock1,pStrBlock2)2493 int StrBlocksHasSameProperties(pStrBlock1, pStrBlock2)
2494 StrBlockInfo *pStrBlock1, *pStrBlock2;
2495 {
2496 if (pStrBlock1->type != pStrBlock2->type) {
2497 return FALSE;
2498 } else if (pStrBlock1->type == SB_SIMPLE) {
2499 StrSegInfo *pStrSeg1=pStrBlock1->seg, *pStrSeg2=pStrBlock2->seg;
2500
2501 if (pStrSeg1->color == pStrSeg2->color &&
2502 pStrSeg1->underline_on == pStrSeg2->underline_on &&
2503 pStrSeg1->overline_on == pStrSeg2->overline_on &&
2504 pStrSeg1->font == pStrSeg2->font &&
2505 pStrSeg1->style == pStrSeg2->style &&
2506 pStrSeg1->sz_unit == pStrSeg2->sz_unit) {
2507 return TRUE;
2508 }
2509 } else if (pStrBlock1->type == SB_CHAR_SPACE) {
2510 return TRUE;
2511 }
2512 return FALSE;
2513 }
2514
2515 static
MergeNextStrBlockWhileDeleting(pStrBlock,pNextStrBlock)2516 void MergeNextStrBlockWhileDeleting(pStrBlock, pNextStrBlock)
2517 StrBlockInfo *pStrBlock, *pNextStrBlock;
2518 /* combine pStrBlock and pNextStrBlock */
2519 {
2520 int len=pStrBlock->seg->dyn_str.sz+pNextStrBlock->seg->dyn_str.sz-1;
2521 char *psz=(char*)malloc(len+1);
2522
2523 if (psz == NULL) FailAllocMessage();
2524 sprintf(psz, "%s%s",
2525 pStrBlock->seg->dyn_str.s, pNextStrBlock->seg->dyn_str.s);
2526 DynStrSet(&pStrBlock->seg->dyn_str, psz);
2527 free(psz);
2528
2529 UnlinkStrBlock(pNextStrBlock);
2530 FreeStrBlock(pNextStrBlock);
2531 }
2532
MergeStrBlocks(pStrBlock,pNextStrBlock)2533 int MergeStrBlocks(pStrBlock, pNextStrBlock)
2534 StrBlockInfo *pStrBlock, *pNextStrBlock;
2535 {
2536 if (pStrBlock->type == SB_SIMPLE && StrBlocksHasSameProperties(pStrBlock,
2537 pNextStrBlock)) {
2538 MergeNextStrBlockWhileDeleting(pStrBlock, pNextStrBlock);
2539 return TRUE;
2540 }
2541 return FALSE;
2542 }
2543
DeleteHighlightedText()2544 void DeleteHighlightedText()
2545 {
2546 MiniLineInfo *pOwnerMiniLine=NULL;
2547 StrBlockInfo *saved_str_block=NULL, *pStrBlock=NULL, *pNextStrBlock=NULL;
2548 int saved_index=INVALID, first_index=0, second_index=0, mode=PAINT_NORM;
2549
2550 if (!textHighlight) return;
2551
2552 /* setup gstTextHighlightInfo */
2553 if (!UpdateTextHighlightInfo()) return;
2554
2555 gstTextHighlightInfo.highlighting = FALSE;
2556 gstTextHighlightInfo.mode = PAINT_NORM;
2557
2558 pStrBlock = saved_str_block = gstTextHighlightInfo.start_str_block_ptr;
2559 saved_index = gstTextHighlightInfo.start_index;
2560 pOwnerMiniLine = pStrBlock->owner_mini_line;
2561
2562 AddToDirtyBBox(&pStrBlock->clean_bbox);
2563
2564 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
2565 DeleteHighlightedTextInStrSeg(pStrBlock->seg, mode, first_index,
2566 second_index);
2567 mode = gstTextHighlightInfo.mode;
2568 pStrBlock = pStrBlock->next;
2569 while (mode != PAINT_NORM) {
2570 if (pStrBlock == NULL) {
2571 /* combine pOwnerMiniLine and pOwnerMiniLine->next */
2572 pNextStrBlock = pOwnerMiniLine->next->first_block;
2573 MergeNextMiniLineWhileDeleting(pOwnerMiniLine);
2574 pStrBlock = pNextStrBlock;
2575 continue;
2576 }
2577 pNextStrBlock = pStrBlock->next;
2578 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
2579 AddToDirtyBBox(&pStrBlock->clean_bbox);
2580 if (mode == PAINT_INV) {
2581 UnlinkStrBlock(pStrBlock);
2582 FreeStrBlock(pStrBlock);
2583 pStrBlock = NULL;
2584 } else {
2585 /* pStrBlock->type better be SB_SIMPLE */
2586 #ifdef _TGIF_DBG /* debug, do not translate */
2587 TgAssert(pStrBlock->type == SB_SIMPLE,
2588 "pStrBlock->type != SB_SIMPLE in DeleteHighlightedText()",
2589 NULL);
2590 #endif /* _TGIF_DBG */
2591 DeleteHighlightedTextInStrSeg(pStrBlock->seg, mode, first_index,
2592 second_index);
2593 }
2594 mode = gstTextHighlightInfo.mode;
2595 pStrBlock = pNextStrBlock;
2596 }
2597 curStrBlock = saved_str_block;
2598 textCurIndex = saved_index;
2599
2600 ResetOnCursorKey(FALSE);
2601 textHighlight = FALSE;
2602
2603 while (*curStrBlock->seg->dyn_str.s == '\0' &&
2604 curStrBlock->next != NULL &&
2605 curStrBlock->next->type == SB_SIMPLE &&
2606 *curStrBlock->next->seg->dyn_str.s == '\0') {
2607 pStrBlock = curStrBlock->next;
2608 UnlinkStrBlock(pStrBlock);
2609 FreeStrBlock(pStrBlock);
2610 pStrBlock = NULL;
2611 }
2612 while (curStrBlock->next != NULL) {
2613 if (!MergeStrBlocks(curStrBlock, curStrBlock->next)) {
2614 break;
2615 }
2616 }
2617 SetTextCurXY();
2618 }
2619
2620 /* --------------------- DoInsertThinSpace() --------------------- */
2621
2622 static
DetermineWhatToDoForSpace(pnSplitAtIndex,pnInsertBefore)2623 void DetermineWhatToDoForSpace(pnSplitAtIndex, pnInsertBefore)
2624 int *pnSplitAtIndex, *pnInsertBefore;
2625 {
2626 if (textCurIndex == 0 && curStrBlock->seg->dyn_str.sz != 1) {
2627 if (curStrBlock->prev == NULL ||
2628 curStrBlock->prev->type != SB_SIMPLE) {
2629 *pnSplitAtIndex = TRUE;
2630 } else {
2631 *pnInsertBefore = TRUE;
2632 }
2633 } else if (textCurIndex == curStrBlock->seg->dyn_str.sz-1) {
2634 if (curStrBlock->next == NULL ||
2635 curStrBlock->next->type != SB_SIMPLE) {
2636 *pnSplitAtIndex = TRUE;
2637 } else {
2638 *pnInsertBefore = FALSE;
2639 }
2640 } else {
2641 *pnSplitAtIndex = TRUE;
2642 }
2643 }
2644
DoInsertThinSpace(thin_space_w)2645 void DoInsertThinSpace(thin_space_w)
2646 int thin_space_w;
2647 {
2648 int split_at_index=FALSE, insert_before=FALSE;
2649 MiniLineInfo *owner_mini_line=curStrBlock->owner_mini_line;
2650 StrBlockInfo *pThinSpaceStrBlock=NewStrBlock();
2651
2652 pThinSpaceStrBlock->type = SB_CHAR_SPACE;
2653 pThinSpaceStrBlock->special_char_w = pThinSpaceStrBlock->w = thin_space_w;
2654 pThinSpaceStrBlock->owner_mini_line = owner_mini_line;
2655
2656 DetermineWhatToDoForSpace(&split_at_index, &insert_before);
2657
2658 if (split_at_index) {
2659 StrBlockInfo *pLeftStrBlock=NULL;
2660 char *psz=UtilStrDup(curStrBlock->seg->dyn_str.s), saved_ch='\0';
2661
2662 if (psz == NULL) FailAllocMessage();
2663
2664 DupStrBlock(curStrBlock, owner_mini_line, &pLeftStrBlock, &pLeftStrBlock);
2665 saved_ch = psz[textCurIndex];
2666 psz[textCurIndex] = '\0';
2667 DynStrSet(&pLeftStrBlock->seg->dyn_str, psz);
2668 psz[textCurIndex] = saved_ch;
2669 DynStrSet(&curStrBlock->seg->dyn_str, &psz[textCurIndex]);
2670 UtilFree(psz);
2671
2672 pLeftStrBlock->prev = curStrBlock->prev;
2673 if (curStrBlock->prev == NULL) {
2674 owner_mini_line->first_block = pLeftStrBlock;
2675 } else {
2676 curStrBlock->prev->next = pLeftStrBlock;
2677 }
2678 pLeftStrBlock->next = pThinSpaceStrBlock;
2679 pThinSpaceStrBlock->prev = pLeftStrBlock;
2680
2681 pThinSpaceStrBlock->next = curStrBlock;
2682 curStrBlock->prev = pThinSpaceStrBlock;
2683
2684 textCurIndex = 0;
2685 } else if (insert_before) {
2686 pThinSpaceStrBlock->prev = curStrBlock->prev;
2687 curStrBlock->prev->next = pThinSpaceStrBlock;
2688 pThinSpaceStrBlock->next = curStrBlock;
2689 curStrBlock->prev = pThinSpaceStrBlock;
2690 } else {
2691 /* insert after */
2692 pThinSpaceStrBlock->next = curStrBlock->next;
2693 curStrBlock->next->prev = pThinSpaceStrBlock;
2694
2695 pThinSpaceStrBlock->prev = curStrBlock;
2696 curStrBlock->next = pThinSpaceStrBlock;
2697 }
2698 }
2699
2700 /* --------------------- InsertHighlightedThinSpace() --------------------- */
2701
2702 static
InsertHighlightedThinSpaceInStrSeg(pStrSeg,mode,first_index,second_index)2703 int InsertHighlightedThinSpaceInStrSeg(pStrSeg, mode, first_index, second_index)
2704 StrSegInfo *pStrSeg;
2705 int mode, first_index, second_index;
2706 /* return TRUE if all done deleting */
2707 {
2708 char *psz=NULL, *psz1=NULL, *psz2=NULL;
2709
2710 switch (mode) {
2711 case PAINT_NORM: break;
2712 case PAINT_INV: break;
2713
2714 case PAINT_NORM_INV:
2715 /* delete the tail */
2716 pStrSeg->dyn_str.s[first_index] = '\0';
2717 if ((psz=UtilStrDup(pStrSeg->dyn_str.s)) == NULL) FailAllocMessage();
2718 DynStrSet(&pStrSeg->dyn_str, psz);
2719 UtilFree(psz);
2720 gstTextHighlightInfo.mode = PAINT_INV;
2721 break;
2722
2723 case PAINT_INV_NORM:
2724 if ((psz=UtilStrDup(&pStrSeg->dyn_str.s[first_index])) == NULL) {
2725 FailAllocMessage();
2726 }
2727 DynStrSet(&pStrSeg->dyn_str, psz);
2728 UtilFree(psz);
2729 gstTextHighlightInfo.mode = PAINT_NORM;
2730 return TRUE;
2731
2732 case PAINT_NORM_INV_NORM:
2733 if ((psz=UtilStrDup(pStrSeg->dyn_str.s)) == NULL) {
2734 FailAllocMessage();
2735 }
2736 for (psz1=(&psz[first_index]), psz2=(&psz[second_index]);
2737 *psz2 != '\0'; psz1++, psz2++) {
2738 *psz1 = *psz2;
2739 }
2740 *psz1 = '\0';
2741 DynStrSet(&pStrSeg->dyn_str, psz);
2742 UtilFree(psz);
2743 gstTextHighlightInfo.mode = PAINT_NORM;
2744 return TRUE;
2745 }
2746 return FALSE;
2747 }
2748
InsertHighlightedThinSpace(thin_space_w)2749 void InsertHighlightedThinSpace(thin_space_w)
2750 int thin_space_w;
2751 {
2752 MiniLineInfo *pOwnerMiniLine=NULL;
2753 StrBlockInfo *saved_str_block=NULL, *pStrBlock=NULL, *pNextStrBlock=NULL;
2754 int saved_index=INVALID, first_index=0, second_index=0, mode=PAINT_NORM;
2755
2756 if (!textHighlight) return;
2757
2758 /* setup gstTextHighlightInfo */
2759 if (!UpdateTextHighlightInfo()) return;
2760
2761 gstTextHighlightInfo.highlighting = FALSE;
2762 gstTextHighlightInfo.mode = PAINT_NORM;
2763
2764 pStrBlock = saved_str_block = gstTextHighlightInfo.start_str_block_ptr;
2765 saved_index = gstTextHighlightInfo.start_index;
2766 pOwnerMiniLine = pStrBlock->owner_mini_line;
2767
2768 AddToDirtyBBox(&pStrBlock->clean_bbox);
2769
2770 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
2771 InsertHighlightedThinSpaceInStrSeg(pStrBlock->seg, mode, first_index,
2772 second_index);
2773 mode = gstTextHighlightInfo.mode;
2774 pStrBlock = pStrBlock->next;
2775 while (mode != PAINT_NORM) {
2776 if (pStrBlock == NULL) {
2777 /* combine pOwnerMiniLine and pOwnerMiniLine->next */
2778 pNextStrBlock = pOwnerMiniLine->next->first_block;
2779 pStrBlock = pNextStrBlock;
2780 continue;
2781 }
2782 pNextStrBlock = pStrBlock->next;
2783 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
2784 AddToDirtyBBox(&pStrBlock->clean_bbox);
2785 if (mode == PAINT_INV) {
2786 UnlinkStrBlock(pStrBlock);
2787 FreeStrBlock(pStrBlock);
2788 pStrBlock = NULL;
2789 } else {
2790 /* pStrBlock->type better be SB_SIMPLE */
2791 #ifdef _TGIF_DBG /* debug, do not translate */
2792 TgAssert(pStrBlock->type == SB_SIMPLE,
2793 "pStrBlock->type != SB_SIMPLE in InsertHighlightedThinSpace()",
2794 NULL);
2795 #endif /* _TGIF_DBG */
2796 InsertHighlightedThinSpaceInStrSeg(pStrBlock->seg, mode, first_index,
2797 second_index);
2798 }
2799 mode = gstTextHighlightInfo.mode;
2800 pStrBlock = pNextStrBlock;
2801 }
2802 curStrBlock = saved_str_block;
2803 textCurIndex = saved_index;
2804
2805 ResetOnCursorKey(FALSE);
2806 textHighlight = FALSE;
2807
2808 while (*curStrBlock->seg->dyn_str.s == '\0' &&
2809 curStrBlock->next != NULL &&
2810 curStrBlock->next->type == SB_SIMPLE &&
2811 *curStrBlock->next->seg->dyn_str.s == '\0') {
2812 pStrBlock = curStrBlock->next;
2813 UnlinkStrBlock(pStrBlock);
2814 FreeStrBlock(pStrBlock);
2815 pStrBlock = NULL;
2816 }
2817 SetTextCurXY();
2818 }
2819
2820 /* --------------------- ShrinkMiniLines() --------------------- */
2821
2822 static
ShrinkMiniLine(pMiniLine,pn_retry)2823 int ShrinkMiniLine(pMiniLine, pn_retry)
2824 MiniLineInfo *pMiniLine;
2825 int *pn_retry;
2826 {
2827 StrBlockInfo *pStrBlock=pMiniLine->first_block;
2828 int changed=FALSE;
2829
2830 while (pStrBlock != NULL) {
2831 StrBlockInfo *pNextStrBlock=pStrBlock->next;
2832 int advance=TRUE;
2833
2834 switch (pStrBlock->type) {
2835 case SB_SIMPLE:
2836 if (pNextStrBlock != NULL && pNextStrBlock->type == SB_SIMPLE) {
2837 if (*pNextStrBlock->seg->dyn_str.s == '\0' ||
2838 StrBlocksHasSameProperties(pStrBlock, pNextStrBlock)) {
2839 MergeNextStrBlockWhileDeleting(pStrBlock, pNextStrBlock);
2840 changed = TRUE;
2841 advance = FALSE;
2842 } else if (*pStrBlock->seg->dyn_str.s == '\0') {
2843 UnlinkStrBlock(pStrBlock);
2844 FreeStrBlock(pStrBlock);
2845 *pn_retry = TRUE;
2846 changed = TRUE;
2847 advance = FALSE;
2848 pStrBlock = pNextStrBlock;
2849 }
2850 }
2851 break;
2852 case SB_CHAR_SPACE:
2853 if (pStrBlock->special_char_w == 0) {
2854 UnlinkStrBlock(pStrBlock);
2855 FreeStrBlock(pStrBlock);
2856 *pn_retry = TRUE;
2857 changed = TRUE;
2858 advance = FALSE;
2859 pStrBlock = pNextStrBlock;
2860 }
2861 break;
2862
2863 case SB_SUPSUB_LEFT:
2864 case SB_SUPSUB_CENTER:
2865 case SB_SUPSUB_RIGHT:
2866 if (pStrBlock->sup != NULL) {
2867 if (ShrinkMiniLines(pStrBlock->sup, pn_retry)) {
2868 changed = TRUE;
2869 }
2870 }
2871 if (pStrBlock->sub != NULL) {
2872 if (ShrinkMiniLines(pStrBlock->sub, pn_retry)) {
2873 changed = TRUE;
2874 }
2875 }
2876 if (pStrBlock->sup != NULL && pStrBlock->sub != NULL &&
2877 BlankMiniLines(pStrBlock->sup) &&
2878 BlankMiniLines(pStrBlock->sub)) {
2879 if ((pStrBlock->type == SB_SUPSUB_CENTER &&
2880 *pStrBlock->seg->dyn_str.s == '\0') ||
2881 pStrBlock->type != SB_SUPSUB_CENTER) {
2882 UnlinkStrBlock(pStrBlock);
2883 FreeStrBlock(pStrBlock);
2884 *pn_retry = TRUE;
2885 changed = TRUE;
2886 advance = FALSE;
2887 pStrBlock = pNextStrBlock;
2888 } else if (pStrBlock->type == SB_SUPSUB_CENTER &&
2889 *pStrBlock->seg->dyn_str.s != '\0') {
2890 if (pStrBlock->sup != NULL) FreeMiniLines(pStrBlock->sup, TRUE);
2891 if (pStrBlock->sub != NULL) FreeMiniLines(pStrBlock->sub, TRUE);
2892 pStrBlock->sup = pStrBlock->sub = NULL;
2893 pStrBlock->type = SB_SIMPLE;
2894 *pn_retry = TRUE;
2895 changed = TRUE;
2896 advance = FALSE;
2897 }
2898 }
2899 break;
2900 }
2901 if (advance) {
2902 pStrBlock = pStrBlock->next;
2903 }
2904 }
2905 return changed;
2906 }
2907
ShrinkMiniLines(minilines,pn_retry)2908 int ShrinkMiniLines(minilines, pn_retry)
2909 MiniLinesInfo *minilines;
2910 int *pn_retry;
2911 {
2912 MiniLineInfo *pMiniLine=NULL;
2913 int changed=FALSE;
2914
2915 for (pMiniLine=minilines->first; pMiniLine != NULL;
2916 pMiniLine=pMiniLine->next) {
2917 if (ShrinkMiniLine(pMiniLine, pn_retry)) {
2918 changed = TRUE;
2919 }
2920 }
2921 return changed;
2922 }
2923
2924 /* --------------------- GetTextXY() --------------------- */
2925
2926 static
GetTextXYInStrSeg(pStrSeg,index_to_match,pn_dx)2927 int GetTextXYInStrSeg(pStrSeg, index_to_match, pn_dx)
2928 StrSegInfo *pStrSeg;
2929 int index_to_match, *pn_dx;
2930 /*
2931 * *pn_x is the amount moved by this routine
2932 */
2933 {
2934 curFont = pStrSeg->font;
2935 curSzUnit = pStrSeg->sz_unit;
2936 curStyle = pStrSeg->style;
2937 SetCanvasFont();
2938 *pn_dx += MyTextWidth(canvasFontPtr, pStrSeg->dyn_str.s, index_to_match);
2939
2940 return TRUE;
2941 }
2942
2943 static
GetTextXYInStrBlock(pStrBlock,pStrBlockToMatch,index_to_match,pn_dx,pn_dy)2944 int GetTextXYInStrBlock(pStrBlock, pStrBlockToMatch, index_to_match,
2945 pn_dx, pn_dy)
2946 StrBlockInfo *pStrBlock;
2947 StrBlockInfo *pStrBlockToMatch;
2948 int index_to_match, *pn_dx, *pn_dy;
2949 /*
2950 * *pn_x and *pn_y are the amount moved by this routine
2951 */
2952 {
2953 int dx=0, dy=0;
2954
2955 switch (pStrBlock->type) {
2956 case SB_SIMPLE:
2957 if (pStrBlockToMatch == pStrBlock) {
2958 return GetTextXYInStrSeg(pStrBlock->seg, index_to_match, pn_dx);
2959 }
2960 break;
2961
2962 case SB_CHAR_SPACE:
2963 if (pStrBlockToMatch == pStrBlock) {
2964 #ifdef _TGIF_DBG /* debug, do not translate */
2965 TgAssert(FALSE,
2966 "StrBlock has type of SB_CHAR_SPACE in GetTextXYInStrBlock()",
2967 NULL);
2968 #endif /* _TGIF_DBG */
2969 if (index_to_match == 1) {
2970 *pn_dx += pStrBlock->special_char_w;
2971 }
2972 return TRUE;
2973 }
2974 break;
2975
2976 case SB_SUPSUB_LEFT:
2977 case SB_SUPSUB_CENTER:
2978 case SB_SUPSUB_RIGHT:
2979 dx = dy = 0;
2980 if (pStrBlock->sup != NULL) {
2981 switch (pStrBlock->type) {
2982 case SB_SUPSUB_LEFT: dx += (-pStrBlock->w); break;
2983 case SB_SUPSUB_CENTER: dx += (-((pStrBlock->w)>>1)); break;
2984 case SB_SUPSUB_RIGHT: break;
2985 }
2986 dy += pStrBlock->sup->baseline_offset;
2987 if (pStrBlock->type == SB_SUPSUB_CENTER) {
2988 dy -= pStrBlock->seg->asc;
2989 }
2990 if (GetTextXYInMiniLines(pStrBlock->sup, pStrBlockToMatch,
2991 index_to_match, pn_dx, pn_dy)) {
2992 *pn_dx -= dx;
2993 *pn_dy += dy;
2994 return TRUE;
2995 }
2996 }
2997 dx = dy = 0;
2998 if (pStrBlock->sub != NULL) {
2999 switch (pStrBlock->type) {
3000 case SB_SUPSUB_LEFT: dx += (-pStrBlock->w); break;
3001 case SB_SUPSUB_CENTER: dx += (-((pStrBlock->w)>>1)); break;
3002 case SB_SUPSUB_RIGHT: break;
3003 }
3004 dy += pStrBlock->sub->baseline_offset;
3005 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3006 dy += pStrBlock->seg->des;
3007 }
3008 if (GetTextXYInMiniLines(pStrBlock->sub, pStrBlockToMatch,
3009 index_to_match, pn_dx, pn_dy)) {
3010 *pn_dx -= dx;
3011 *pn_dy += dy;
3012 return TRUE;
3013 }
3014 }
3015 dx = dy = 0;
3016 if (pStrBlock->type == SB_SUPSUB_CENTER &&
3017 pStrBlockToMatch == pStrBlock) {
3018 dx -= ((pStrBlock->w-pStrBlock->seg->w)>>1);
3019 if (GetTextXYInStrSeg(pStrBlock->seg, index_to_match, pn_dx)) {
3020 *pn_dx -= dx;
3021 *pn_dy += dy;
3022 return TRUE;
3023 }
3024 break;
3025 }
3026 break;
3027 }
3028 return FALSE;
3029 }
3030
3031 static
GetTextXYInMiniLine(pMiniLine,pStrBlockToMatch,index_to_match,pn_dx,pn_dy)3032 int GetTextXYInMiniLine(pMiniLine, pStrBlockToMatch, index_to_match,
3033 pn_dx, pn_dy)
3034 MiniLineInfo *pMiniLine;
3035 StrBlockInfo *pStrBlockToMatch;
3036 int index_to_match, *pn_dx, *pn_dy;
3037 /*
3038 * *pn_x and *pn_y are the amount moved by this routine
3039 */
3040 {
3041 StrBlockInfo *pStrBlock=NULL;
3042
3043 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
3044 pStrBlock=pStrBlock->next) {
3045 int w=pStrBlock->w;
3046
3047 if (GetTextXYInStrBlock(pStrBlock, pStrBlockToMatch, index_to_match,
3048 pn_dx, pn_dy)) {
3049 return TRUE;
3050 }
3051 *pn_dx += w;
3052 }
3053 return FALSE;
3054 }
3055
GetTextXYInMiniLines(minilines,pStrBlockToMatch,index_to_match,pn_dx,pn_dy)3056 int GetTextXYInMiniLines(minilines, pStrBlockToMatch, index_to_match,
3057 pn_dx, pn_dy)
3058 MiniLinesInfo *minilines;
3059 StrBlockInfo *pStrBlockToMatch;
3060 int index_to_match, *pn_dx, *pn_dy;
3061 /*
3062 * *pn_x and *pn_y are the amount moved by this routine
3063 */
3064 {
3065 MiniLineInfo *pMiniLine=NULL;
3066 int v_space=minilines->v_space;
3067 int dx=0, dy=0;
3068
3069 for (pMiniLine=minilines->first; pMiniLine != NULL;
3070 pMiniLine=pMiniLine->next) {
3071 int saved_dx=(*pn_dx), saved_dy=(*pn_dy);
3072
3073 #ifdef _TGIF_DBG /* debug, do not translate */
3074 if (pMiniLine == minilines->first) {
3075 TgAssert(pMiniLine->v_gap == 0,
3076 "First mini_line has non-zero v_gap in GetTextXYInMiniLines()",
3077 NULL);
3078 }
3079 #endif /* _TGIF_DBG */
3080 dy += pMiniLine->v_gap;
3081
3082 switch (minilines->just) {
3083 case JUST_L: break;
3084 case JUST_C: dx += ((pMiniLine->w)>>1); break;
3085 case JUST_R: dx += pMiniLine->w; break;
3086 }
3087 if (GetTextXYInMiniLine(pMiniLine, pStrBlockToMatch, index_to_match,
3088 pn_dx, pn_dy)) {
3089 *pn_dx -= dx;
3090 *pn_dy += dy;
3091 return TRUE;
3092 }
3093 *pn_dx = saved_dx;
3094 *pn_dy = saved_dy;
3095
3096 switch (minilines->just) {
3097 case JUST_L: break;
3098 case JUST_C: dx -= ((pMiniLine->w)>>1); break;
3099 case JUST_R: dx -= pMiniLine->w; break;
3100 }
3101 dy += pMiniLine->des + v_space;
3102 if (pMiniLine->next != NULL) {
3103 dy += pMiniLine->next->asc;
3104 }
3105 }
3106 return FALSE;
3107 }
3108
GetTextXY(pStrBlock,nIndex,pn_x,pn_baseline_y)3109 void GetTextXY(pStrBlock, nIndex, pn_x, pn_baseline_y)
3110 StrBlockInfo *pStrBlock;
3111 int nIndex, *pn_x, *pn_baseline_y;
3112 {
3113 int dx=0, dy=0;
3114 struct TextRec *text_ptr=curTextObj->detail.t;
3115
3116 PushCurFont();
3117 GetTextXYInMiniLines(&text_ptr->minilines, pStrBlock, nIndex,
3118 &dx, &dy);
3119 PopCurFont();
3120
3121 if (pn_x != NULL) {
3122 *pn_x = textOrigX + dx;
3123 }
3124 if (pn_baseline_y != NULL) {
3125 *pn_baseline_y = textOrigBaselineY + dy;
3126 }
3127 }
3128
3129 /* --------------------- SetTextCurXY() --------------------- */
3130
SetTextCurXY()3131 void SetTextCurXY()
3132 /* set textCurX & textCurBaselineY according to curStrBlock & textCurIndex */
3133 {
3134 GetTextXY(curStrBlock, textCurIndex, &textCurX, &textCurBaselineY);
3135 }
3136
3137 /* --------------------- SetTextEndXY() --------------------- */
3138
SetTextEndXY()3139 void SetTextEndXY()
3140 /* set textEndX & textEndBaselineY according to endStrBlock & textEndIndex */
3141 {
3142 GetTextXY(endStrBlock, textEndIndex, &textEndX, &textEndBaselineY);
3143 }
3144
3145 /* --------------------- CurStrBlockInMiniLines() --------------------- */
3146
CurStrBlockInStrBlock(pStrBlock)3147 int CurStrBlockInStrBlock(pStrBlock)
3148 StrBlockInfo *pStrBlock;
3149 {
3150 switch (pStrBlock->type) {
3151 case SB_SIMPLE:
3152 if (curStrBlock == pStrBlock) {
3153 return TRUE;
3154 }
3155 break;
3156
3157 case SB_CHAR_SPACE:
3158 if (curStrBlock == pStrBlock) {
3159 for (pStrBlock=pStrBlock->prev; pStrBlock != NULL;
3160 pStrBlock=pStrBlock->prev) {
3161 if (pStrBlock->type == SB_SIMPLE) {
3162 curStrBlock = pStrBlock;
3163 textCurIndex = pStrBlock->seg->dyn_str.sz-1;
3164 #ifdef _TGIF_DBG /* debug, do not translate */
3165 TgAssert(FALSE,
3166 "curStrBlock->type is SB_CHAR_SPACE in CurStrBlockInStrBlock()",
3167 "Fixed by returning to end of the previous SB_SIMPLE block");
3168 #endif /* _TGIF_DBG */
3169 return TRUE;
3170 }
3171 }
3172 #ifdef _TGIF_DBG /* debug, do not translate */
3173 TgAssert(FALSE,
3174 "curStrBlock->type is SB_CHAR_SPACE in CurStrBlockInStrBlock()",
3175 "Don't know how to fix this one");
3176 #endif /* _TGIF_DBG */
3177 return FALSE;
3178 }
3179 break;
3180
3181 case SB_SUPSUB_LEFT:
3182 case SB_SUPSUB_CENTER:
3183 case SB_SUPSUB_RIGHT:
3184 if (pStrBlock->sup != NULL) {
3185 if (CurStrBlockInMiniLines(pStrBlock->sup)) {
3186 return TRUE;
3187 }
3188 }
3189 if (pStrBlock->sub != NULL) {
3190 if (CurStrBlockInMiniLines(pStrBlock->sub)) {
3191 return TRUE;
3192 }
3193 }
3194 if (pStrBlock->type == SB_SUPSUB_CENTER &&
3195 curStrBlock == pStrBlock) {
3196 return TRUE;
3197 }
3198 break;
3199 }
3200 return FALSE;
3201 }
3202
CurStrBlockInMiniLine(pMiniLine)3203 int CurStrBlockInMiniLine(pMiniLine)
3204 MiniLineInfo *pMiniLine;
3205 {
3206 StrBlockInfo *pStrBlock=NULL;
3207
3208 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
3209 pStrBlock=pStrBlock->next) {
3210 if (CurStrBlockInStrBlock(pStrBlock)) {
3211 return TRUE;
3212 }
3213 }
3214 return FALSE;
3215 }
3216
CurStrBlockInMiniLines(minilines)3217 int CurStrBlockInMiniLines(minilines)
3218 MiniLinesInfo *minilines;
3219 {
3220 MiniLineInfo *pMiniLine=NULL;
3221
3222 for (pMiniLine=minilines->first; pMiniLine != NULL;
3223 pMiniLine=pMiniLine->next) {
3224 if (CurStrBlockInMiniLine(pMiniLine)) {
3225 return TRUE;
3226 }
3227 }
3228 return FALSE;
3229 }
3230
3231 /* --------------------- GetCursorPositionInMiniLines() --------------------- */
3232
3233 static
GetCursorPositionInStrSeg(pStrSeg,dx,pn_dx,ppStrBlock,pnIndex)3234 void GetCursorPositionInStrSeg(pStrSeg, dx, pn_dx, ppStrBlock, pnIndex)
3235 StrSegInfo *pStrSeg;
3236 int dx, *pn_dx, *pnIndex;
3237 StrBlockInfo **ppStrBlock;
3238 /*
3239 * dx is relative to the left side of the string segment
3240 * dy is relative to the baseline of the string segment
3241 * *pn_x is the amount moved by this routine
3242 */
3243 {
3244 char *psz=NULL;
3245 int inc=0, index=0;
3246
3247 curFont = pStrSeg->font;
3248 curSzUnit = pStrSeg->sz_unit;
3249 curStyle = pStrSeg->style;
3250 SetCanvasFont();
3251 inc = (canvasFontDoubleByte ? 2 : 1);
3252
3253 for (psz=pStrSeg->dyn_str.s; *psz != '\0'; psz=(&psz[inc]), index+=inc) {
3254 int w=MyTextWidth(canvasFontPtr, psz, inc);
3255
3256 if (dx < (w>>1)) {
3257 break;
3258 }
3259 dx -= w;
3260 *pn_dx += w;
3261 }
3262 *pnIndex = index;
3263 }
3264
3265 static
GetCursorPositionInStrBlock(pStrBlock,dx,dy,pn_dx,pn_dy,ppStrBlock,pnIndex)3266 void GetCursorPositionInStrBlock(pStrBlock, dx, dy, pn_dx, pn_dy, ppStrBlock,
3267 pnIndex)
3268 StrBlockInfo *pStrBlock;
3269 int dx, dy, *pn_dx, *pn_dy, *pnIndex;
3270 StrBlockInfo **ppStrBlock;
3271 /*
3272 * dx is relative to the left side of the string block
3273 * dy is relative to the baseline of the string block
3274 * *pn_x and *pn_y are the amount moved by this routine
3275 */
3276 {
3277 int which=USE_SEG, saved_dx=dx, saved_dy=dy;
3278
3279 switch (pStrBlock->type) {
3280 case SB_SIMPLE:
3281 GetCursorPositionInStrSeg(pStrBlock->seg, dx, pn_dx, ppStrBlock, pnIndex);
3282 *ppStrBlock = pStrBlock;
3283 break;
3284
3285 case SB_CHAR_SPACE:
3286 #ifdef _TGIF_DBG /* debug, do not translate */
3287 TgAssert(FALSE,
3288 "StrBlock has type SB_CHAR_SPACE in GetCursorPositionInStrBlock()",
3289 NULL);
3290 #endif /* _TGIF_DBG */
3291 *ppStrBlock = pStrBlock;
3292 *pn_dx += pStrBlock->special_char_w;
3293 break;
3294
3295 case SB_SUPSUB_LEFT:
3296 case SB_SUPSUB_CENTER:
3297 case SB_SUPSUB_RIGHT:
3298 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3299 which = USE_SUB;
3300 if (pStrBlock->sup != NULL) {
3301 if (dy < (-pStrBlock->seg->asc)+pStrBlock->sup->baseline_offset-
3302 pStrBlock->sup->first->asc+pStrBlock->sup->h) {
3303 which = USE_SUP;
3304 }
3305 }
3306 if (which == USE_SUB) {
3307 if (dy < pStrBlock->seg->des) {
3308 which = USE_SEG;
3309 }
3310 }
3311 } else {
3312 if (pStrBlock->sup != NULL && pStrBlock->sub != NULL) {
3313 int y=0, half_h=0;
3314
3315 y = dy+pStrBlock->asc;
3316 half_h = ((pStrBlock->asc+pStrBlock->des)>>1);
3317 if (y < half_h) {
3318 which = USE_SUP;
3319 } else {
3320 which = USE_SUB;
3321 }
3322 } else if (pStrBlock->sup != NULL) {
3323 which = USE_SUP;
3324 } else {
3325 which = USE_SUB;
3326 }
3327 }
3328 switch (pStrBlock->type) {
3329 case SB_SUPSUB_LEFT: dx += (-pStrBlock->w); break;
3330 case SB_SUPSUB_CENTER: dx += (-((pStrBlock->w)>>1)); break;
3331 case SB_SUPSUB_RIGHT: break;
3332 }
3333
3334 switch (which) {
3335 case USE_SUP:
3336 dy += pStrBlock->sup->baseline_offset;
3337 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3338 dy -= pStrBlock->seg->asc;
3339 }
3340 GetCursorPositionInMiniLines(pStrBlock->sup, dx, dy, pn_dx, pn_dy,
3341 ppStrBlock, pnIndex);
3342 break;
3343 case USE_SUB:
3344 dy += pStrBlock->sub->baseline_offset;
3345 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3346 dy += pStrBlock->seg->des;
3347 }
3348 GetCursorPositionInMiniLines(pStrBlock->sub, dx, dy, pn_dx, pn_dy,
3349 ppStrBlock, pnIndex);
3350 break;
3351 case USE_SEG:
3352 dx += ((pStrBlock->seg->w)>>1);
3353 GetCursorPositionInStrSeg(pStrBlock->seg, dx, pn_dx, ppStrBlock,
3354 pnIndex);
3355 *ppStrBlock = pStrBlock;
3356 break;
3357 }
3358 *pn_dx += saved_dx - dx;
3359 *pn_dy += dy - saved_dy;
3360 break;
3361 }
3362 }
3363
3364 static
GetCursorPositionInMiniLine(pMiniLine,dx,dy,pn_dx,pn_dy,ppStrBlock,pnIndex)3365 void GetCursorPositionInMiniLine(pMiniLine, dx, dy, pn_dx, pn_dy, ppStrBlock,
3366 pnIndex)
3367 MiniLineInfo *pMiniLine;
3368 int dx, dy, *pn_dx, *pn_dy, *pnIndex;
3369 StrBlockInfo **ppStrBlock;
3370 /*
3371 * dx is relative to the left side of the miniline
3372 * dy is relative to the baseline of the miniline
3373 * *pn_x and *pn_y are the amount moved by this routine
3374 */
3375 {
3376 StrBlockInfo *pStrBlock=NULL;
3377
3378 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
3379 pStrBlock=pStrBlock->next) {
3380 int w=pStrBlock->w;
3381
3382 if (pStrBlock->type != SB_CHAR_SPACE &&
3383 (pStrBlock->next == NULL || dx < w)) {
3384 GetCursorPositionInStrBlock(pStrBlock, dx, dy, pn_dx, pn_dy,
3385 ppStrBlock, pnIndex);
3386 return;
3387 }
3388 dx -= w;
3389 *pn_dx += w;
3390 }
3391 }
3392
GetCursorPositionInMiniLines(minilines,dx,dy,pn_dx,pn_dy,ppStrBlock,pnIndex)3393 int GetCursorPositionInMiniLines(minilines, dx, dy, pn_dx, pn_dy, ppStrBlock,
3394 pnIndex)
3395 MiniLinesInfo *minilines;
3396 int dx, dy, *pn_dx, *pn_dy, *pnIndex;
3397 StrBlockInfo **ppStrBlock;
3398 /*
3399 * returns 0 if *pn_dx and *pn_dy are set
3400 * returns 1 if the caller needs to figure out where the end is
3401 * dx is relative to the origin of the miniline
3402 * dy is relative to the baseline of the miniline
3403 * *pn_x and *pn_y are the amount moved by this routine
3404 */
3405 {
3406 MiniLineInfo *pMiniLine=NULL;
3407 int v_space=minilines->v_space;
3408 int saved_dx=dx, saved_dy=dy;
3409
3410 for (pMiniLine=minilines->first; pMiniLine != NULL;
3411 pMiniLine=pMiniLine->next) {
3412 #ifdef _TGIF_DBG /* debug, do not translate */
3413 if (pMiniLine == minilines->first) {
3414 TgAssert(pMiniLine->v_gap == 0,
3415 "First mini_line has non-zero v_gap in GetCursorPositionInMiniLines()",
3416 NULL);
3417 }
3418 #endif /* _TGIF_DBG */
3419 dy -= pMiniLine->v_gap;
3420 if ((pMiniLine->next == NULL && minilines->owner_block != NULL) ||
3421 dy < pMiniLine->des+minilines->v_space) {
3422 switch (minilines->just) {
3423 case JUST_L: break;
3424 case JUST_C: dx += ((pMiniLine->w)>>1); break;
3425 case JUST_R: dx += pMiniLine->w; break;
3426 }
3427 GetCursorPositionInMiniLine(pMiniLine, dx, dy,
3428 pn_dx, pn_dy, ppStrBlock, pnIndex);
3429 *pn_dx += saved_dx - dx;
3430 *pn_dy += saved_dy - dy;
3431 return 0;
3432 }
3433 dy -= pMiniLine->des + v_space;
3434 if (pMiniLine->next != NULL) {
3435 dy -= pMiniLine->next->asc;
3436 }
3437 }
3438 #ifdef _TGIF_DBG /* debug, do not translate */
3439 TgAssert(minilines->owner_block == NULL,
3440 "Invalid position reached in GetCursorPositionInMiniLines()",
3441 NULL);
3442 #endif /* _TGIF_DBG */
3443 return 1;
3444 }
3445
3446 /* --------------------- SameProperty() --------------------- */
3447
SameProperty(lWhich,nValue,pStrSeg,nCheckDoubleByte)3448 int SameProperty(lWhich, nValue, pStrSeg, nCheckDoubleByte)
3449 long lWhich;
3450 int nValue, nCheckDoubleByte;
3451 StrSegInfo *pStrSeg;
3452 /*
3453 * If lWhich is PROP_MASK_TEXT_FONT and nCheckDoubleByte is TRUE, if
3454 * pStrSeg->double_byte != IsFontDoubleByte(nValue), this function
3455 * should return TRUE because the font cannot be changed.
3456 */
3457 {
3458 switch (lWhich) {
3459 case PROP_MASK_COLOR: return (pStrSeg->color == nValue);
3460 case PROP_MASK_TEXT_FONT:
3461 if (pStrSeg->font == nValue) return TRUE;
3462 return (nCheckDoubleByte && (pStrSeg->double_byte !=
3463 IsFontDoubleByte(nValue)));
3464 case PROP_MASK_TEXT_STYLE: return (pStrSeg->style == nValue);
3465 case PROP_MASK_TEXT_SZ_UNIT: return (pStrSeg->sz_unit == nValue);
3466 case PROP_MASK_UNDERLINE_ON: return (pStrSeg->underline_on == nValue);
3467 case PROP_MASK_OVERLINE_ON: return (pStrSeg->overline_on == nValue);
3468 }
3469 return FALSE;
3470 }
3471
3472 /* --------------------- SetMiniLinesProperty() --------------------- */
3473
SetStrSegProperty(lWhich,nValue,pStrSeg)3474 int SetStrSegProperty(lWhich, nValue, pStrSeg)
3475 long lWhich;
3476 int nValue;
3477 StrSegInfo *pStrSeg;
3478 {
3479 int changed=FALSE, got_requested_size=TRUE;
3480
3481 PushCurFont();
3482
3483 switch (lWhich) {
3484 case PROP_MASK_COLOR:
3485 if (pStrSeg->color != nValue) {
3486 pStrSeg->color = nValue;
3487 UtilStrCpyN(pStrSeg->color_str, sizeof(pStrSeg->color_str),
3488 colorMenuItems[pStrSeg->color]);
3489 changed = TRUE;
3490 }
3491 break;
3492 case PROP_MASK_TEXT_FONT:
3493 if (pStrSeg->font != nValue &&
3494 pStrSeg->double_byte == IsFontDoubleByte(nValue)) {
3495 if (TrySetCanvasFont(nValue, pStrSeg->style,
3496 SzUnitToFontSize(pStrSeg->sz_unit), FALSE,
3497 &got_requested_size)) {
3498 pStrSeg->font = nValue;
3499 if (pStrSeg->double_byte) {
3500 pStrSeg->double_byte_vertical = canvasFontDoubleByteVertical;
3501 pStrSeg->double_byte_mod_bytes = canvasFontDoubleByteModBytes;
3502 } else {
3503 pStrSeg->double_byte_vertical = FALSE;
3504 pStrSeg->double_byte_mod_bytes = FALSE;
3505 }
3506 if (!got_requested_size) {
3507 pStrSeg->sz_unit = FontSizeToSzUnit(canvasFontSize);
3508 }
3509 changed = TRUE;
3510 }
3511 }
3512 break;
3513 case PROP_MASK_TEXT_STYLE:
3514 if (pStrSeg->style != nValue) {
3515 if (TrySetCanvasFont(pStrSeg->font, nValue,
3516 SzUnitToFontSize(pStrSeg->sz_unit), FALSE,
3517 &got_requested_size)) {
3518 pStrSeg->style = nValue;
3519 if (!got_requested_size) {
3520 pStrSeg->sz_unit = FontSizeToSzUnit(canvasFontSize);
3521 }
3522 changed = TRUE;
3523 }
3524 }
3525 break;
3526 case PROP_MASK_TEXT_SZ_UNIT:
3527 if (pStrSeg->sz_unit != nValue) {
3528 if (TrySetCanvasFont(pStrSeg->font, pStrSeg->style,
3529 SzUnitToFontSize(nValue), TRUE, &got_requested_size) &&
3530 got_requested_size) {
3531 pStrSeg->sz_unit = nValue;
3532 changed = TRUE;
3533 }
3534 }
3535 break;
3536 case PROP_MASK_UNDERLINE_ON:
3537 if (pStrSeg->underline_on != nValue) {
3538 pStrSeg->underline_on = nValue;
3539 changed = TRUE;
3540 }
3541 break;
3542 case PROP_MASK_OVERLINE_ON:
3543 if (pStrSeg->overline_on != nValue) {
3544 pStrSeg->overline_on = nValue;
3545 changed = TRUE;
3546 }
3547 break;
3548 }
3549 PopCurFont();
3550
3551 return changed;
3552 }
3553
3554 static
SetStrBlockProperty(lWhich,nValue,pStrBlock)3555 int SetStrBlockProperty(lWhich, nValue, pStrBlock)
3556 long lWhich;
3557 int nValue;
3558 StrBlockInfo *pStrBlock;
3559 {
3560 int changed=FALSE;
3561
3562 switch (pStrBlock->type) {
3563 case SB_SIMPLE:
3564 changed = SetStrSegProperty(lWhich, nValue, pStrBlock->seg);
3565 break;
3566
3567 case SB_CHAR_SPACE:
3568 break;
3569
3570 case SB_SUPSUB_LEFT:
3571 case SB_SUPSUB_CENTER:
3572 case SB_SUPSUB_RIGHT:
3573 if (pStrBlock->sup != NULL) {
3574 if (SetMiniLinesProperty(lWhich, nValue, pStrBlock->sup)) {
3575 changed = TRUE;
3576 }
3577 }
3578 if (pStrBlock->sub != NULL) {
3579 if (SetMiniLinesProperty(lWhich, nValue, pStrBlock->sub)) {
3580 changed = TRUE;
3581 }
3582 }
3583 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3584 if (SetStrSegProperty(lWhich, nValue, pStrBlock->seg)) {
3585 changed = TRUE;
3586 }
3587 }
3588 break;
3589 }
3590 return changed;
3591 }
3592
3593 static
SetMiniLineProperty(lWhich,nValue,pMiniLine)3594 int SetMiniLineProperty(lWhich, nValue, pMiniLine)
3595 long lWhich;
3596 int nValue;
3597 MiniLineInfo *pMiniLine;
3598 {
3599 StrBlockInfo *pStrBlock=NULL;
3600 int changed=FALSE;
3601
3602 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
3603 pStrBlock=pStrBlock->next) {
3604 if (SetStrBlockProperty(lWhich, nValue, pStrBlock)) {
3605 changed = TRUE;
3606 }
3607 }
3608 return changed;
3609 }
3610
SetMiniLinesProperty(lWhich,nValue,minilines)3611 int SetMiniLinesProperty(lWhich, nValue, minilines)
3612 long lWhich;
3613 int nValue;
3614 MiniLinesInfo *minilines;
3615 {
3616 MiniLineInfo *pMiniLine=NULL;
3617 int changed=FALSE;
3618
3619 for (pMiniLine=minilines->first; pMiniLine != NULL;
3620 pMiniLine=pMiniLine->next) {
3621 if (SetMiniLineProperty(lWhich, nValue, pMiniLine)) {
3622 changed = TRUE;
3623 }
3624 }
3625 return changed;
3626 }
3627
3628 /* -------------------- ChangeHighlightedTextProperty() -------------------- */
3629
3630 static
ChangeStrSegPropertyForTail(pStrBlock,first_index,lWhich,nValue)3631 int ChangeStrSegPropertyForTail(pStrBlock, first_index, lWhich, nValue)
3632 StrBlockInfo *pStrBlock;
3633 int first_index, nValue;
3634 long lWhich;
3635 /* return TRUE anything is changed */
3636 {
3637 StrSegInfo *pStrSeg=pStrBlock->seg;
3638 StrBlockInfo *pNewStrBlock=NULL;
3639 MiniLineInfo *owner_mini_line=pStrBlock->owner_mini_line;
3640 int changed=FALSE;
3641
3642 DupStrBlock(pStrBlock, owner_mini_line, &pNewStrBlock,
3643 &pNewStrBlock);
3644 DynStrSet(&pNewStrBlock->seg->dyn_str,
3645 &pStrSeg->dyn_str.s[first_index]);
3646 pStrSeg->dyn_str.s[first_index] = '\0';
3647 DynStrSet(&pStrSeg->dyn_str, pStrSeg->dyn_str.s);
3648 if (!SetStrSegProperty(lWhich, nValue, pNewStrBlock->seg)) {
3649 /*
3650 * don't call UnlinkStrBlock() because DupStrBlock() does not
3651 * insert pNewStrBlock into owner_mini_line
3652 */
3653 FreeStrBlock(pNewStrBlock);
3654 } else {
3655 /* insert after */
3656 pNewStrBlock->next = pStrBlock->next;
3657 if (pStrBlock->next == NULL) {
3658 owner_mini_line->last_block = pNewStrBlock;
3659 } else {
3660 pStrBlock->next->prev = pNewStrBlock;
3661 }
3662 pNewStrBlock->prev = pStrBlock;
3663 pStrBlock->next = pNewStrBlock;
3664 changed = TRUE;
3665 }
3666 if (changed) {
3667 if (pStrBlock == gstTextHighlightInfo.start_str_block_ptr) {
3668 if (curStrBlock == endStrBlock) {
3669 if (textCurIndex == first_index) {
3670 curStrBlock = endStrBlock = pNewStrBlock;
3671 textCurIndex = 0;
3672 textEndIndex = endStrBlock->seg->dyn_str.sz-1;
3673 } else {
3674 endStrBlock = curStrBlock = pNewStrBlock;
3675 textEndIndex = 0;
3676 textCurIndex = endStrBlock->seg->dyn_str.sz-1;
3677 }
3678 } else if (pStrBlock == curStrBlock) {
3679 curStrBlock = pNewStrBlock;
3680 textCurIndex = 0;
3681 } else {
3682 endStrBlock = pNewStrBlock;
3683 textEndIndex = 0;
3684 }
3685 }
3686 }
3687 return changed;
3688 }
3689
3690 static
ChangeStrSegPropertyForHead(pStrBlock,first_index,lWhich,nValue)3691 int ChangeStrSegPropertyForHead(pStrBlock, first_index, lWhich, nValue)
3692 StrBlockInfo *pStrBlock;
3693 int first_index, nValue;
3694 long lWhich;
3695 /* return TRUE anything is changed */
3696 {
3697 StrSegInfo *pStrSeg=pStrBlock->seg;
3698 StrBlockInfo *pNewStrBlock=NULL;
3699 MiniLineInfo *owner_mini_line=pStrBlock->owner_mini_line;
3700 char saved_ch=pStrSeg->dyn_str.s[first_index];
3701 int changed=FALSE;
3702
3703 pStrSeg->dyn_str.s[first_index] = '\0';
3704 DupStrBlock(pStrBlock, owner_mini_line, &pNewStrBlock,
3705 &pNewStrBlock);
3706 DynStrSet(&pNewStrBlock->seg->dyn_str, pStrSeg->dyn_str.s);
3707 pStrSeg->dyn_str.s[first_index] = saved_ch;
3708 DynStrSet(&pStrSeg->dyn_str, &pStrSeg->dyn_str.s[first_index]);
3709
3710 if (!SetStrSegProperty(lWhich, nValue, pNewStrBlock->seg)) {
3711 /*
3712 * don't call UnlinkStrBlock() because DupStrBlock() does not
3713 * insert pNewStrBlock into owner_mini_line
3714 */
3715 FreeStrBlock(pNewStrBlock);
3716 } else {
3717 /* insert before */
3718 pNewStrBlock->prev = pStrBlock->prev;
3719 if (pStrBlock->prev == NULL) {
3720 owner_mini_line->first_block = pNewStrBlock;
3721 } else {
3722 pStrBlock->prev->next = pNewStrBlock;
3723 }
3724 pNewStrBlock->next = pStrBlock;
3725 pStrBlock->prev = pNewStrBlock;
3726 changed = TRUE;
3727 }
3728 if (changed) {
3729 if (pStrBlock == gstTextHighlightInfo.end_str_block_ptr) {
3730 if (curStrBlock == endStrBlock) {
3731 if (textCurIndex == first_index) {
3732 curStrBlock = endStrBlock = pNewStrBlock;
3733 textCurIndex = 0;
3734 textEndIndex = endStrBlock->seg->dyn_str.sz-1;
3735 } else {
3736 endStrBlock = curStrBlock = pNewStrBlock;
3737 textEndIndex = 0;
3738 textCurIndex = endStrBlock->seg->dyn_str.sz-1;
3739 }
3740 } else if (pStrBlock == curStrBlock) {
3741 textCurIndex = 0;
3742 } else {
3743 textEndIndex = 0;
3744 }
3745 }
3746 }
3747 return changed;
3748 }
3749
3750 static
ChangeStrSegPropertyForMiddle(pStrBlock,first_index,second_index,lWhich,nValue)3751 int ChangeStrSegPropertyForMiddle(pStrBlock, first_index, second_index, lWhich,
3752 nValue)
3753 StrBlockInfo *pStrBlock;
3754 int first_index, second_index, nValue;
3755 long lWhich;
3756 /* return TRUE anything is changed */
3757 {
3758 StrSegInfo *pStrSeg=pStrBlock->seg;
3759 StrBlockInfo *pNewStrBlock=NULL;
3760 MiniLineInfo *owner_mini_line=pStrBlock->owner_mini_line;
3761 int changed=FALSE;
3762
3763 DupStrBlock(pStrBlock, owner_mini_line, &pNewStrBlock,
3764 &pNewStrBlock);
3765 if (!SetStrSegProperty(lWhich, nValue, pNewStrBlock->seg)) {
3766 /*
3767 * don't call UnlinkStrBlock() because DupStrBlock() does not
3768 * insert pNewStrBlock into owner_mini_line
3769 */
3770 FreeStrBlock(pNewStrBlock);
3771 } else {
3772 /* split */
3773 StrBlockInfo *pLeftStrBlock=NULL;
3774 char *psz=NULL, *psz1=NULL, *psz2=NULL, saved_ch='\0';
3775
3776 DupStrBlock(pStrBlock, owner_mini_line, &pLeftStrBlock,
3777 &pLeftStrBlock);
3778 if ((psz=UtilStrDup(pStrSeg->dyn_str.s)) == NULL) {
3779 FailAllocMessage();
3780 }
3781 saved_ch = psz[first_index];
3782 psz[first_index] = '\0';
3783 DynStrSet(&pLeftStrBlock->seg->dyn_str, psz);
3784 psz[first_index] = saved_ch;
3785 DynStrSet(&pStrBlock->seg->dyn_str, &psz[second_index]);
3786 psz[second_index] = '\0';
3787
3788 for (psz1=psz, psz2=(&psz[first_index]); *psz2 != '\0'; ) {
3789 *psz1++ = *psz2++;
3790 }
3791 *psz1 = '\0';
3792 DynStrSet(&pNewStrBlock->seg->dyn_str, psz);
3793 UtilFree(psz);
3794
3795 pLeftStrBlock->prev = pStrBlock->prev;
3796 if (pStrBlock->prev == NULL) {
3797 owner_mini_line->first_block = pLeftStrBlock;
3798 } else {
3799 pStrBlock->prev->next = pLeftStrBlock;
3800 }
3801 pLeftStrBlock->next = pNewStrBlock;
3802 pNewStrBlock->prev = pLeftStrBlock;
3803
3804 pNewStrBlock->next = pStrBlock;
3805 pStrBlock->prev = pNewStrBlock;
3806
3807 changed = TRUE;
3808 }
3809 if (changed) {
3810 if (pStrBlock == gstTextHighlightInfo.end_str_block_ptr) {
3811 if (curStrBlock == endStrBlock) {
3812 if (textCurIndex == first_index) {
3813 curStrBlock = endStrBlock = pNewStrBlock;
3814 textCurIndex = 0;
3815 textEndIndex = endStrBlock->seg->dyn_str.sz-1;
3816 } else {
3817 endStrBlock = curStrBlock = pNewStrBlock;
3818 textEndIndex = 0;
3819 textCurIndex = endStrBlock->seg->dyn_str.sz-1;
3820 }
3821 }
3822 }
3823 }
3824 return changed;
3825 }
3826
3827 static
ChangePropertyForHighlightedTextInStrSeg(pStrBlock,mode,first_index,second_index,lWhich,nValue)3828 int ChangePropertyForHighlightedTextInStrSeg(pStrBlock, mode, first_index,
3829 second_index, lWhich, nValue)
3830 StrBlockInfo *pStrBlock;
3831 int mode, first_index, second_index, nValue;
3832 long lWhich;
3833 /* return TRUE anything is changed */
3834 {
3835 StrSegInfo *pStrSeg=pStrBlock->seg;
3836 int changed=FALSE;
3837
3838 switch (mode) {
3839 case PAINT_NORM: break;
3840
3841 case PAINT_INV:
3842 /* can only get here if pStrBlock->type is SB_SIMPLE */
3843 changed = SetStrSegProperty(lWhich, nValue, pStrSeg);
3844 break;
3845
3846 case PAINT_NORM_INV:
3847 /* change the tail */
3848 if (SameProperty(lWhich, nValue, pStrSeg, TRUE)) {
3849 /* nothing need to change */
3850 } else if (first_index == pStrSeg->dyn_str.sz-1) {
3851 /* nothing need to change */
3852 } else {
3853 changed = ChangeStrSegPropertyForTail(pStrBlock, first_index, lWhich,
3854 nValue);
3855 }
3856 gstTextHighlightInfo.mode = PAINT_INV;
3857 break;
3858
3859 case PAINT_INV_NORM:
3860 /* change the head */
3861 if (SameProperty(lWhich, nValue, pStrSeg, TRUE)) {
3862 /* nothing need to change */
3863 } else if (first_index == 0) {
3864 /* nothing need to change */
3865 } else {
3866 changed = ChangeStrSegPropertyForHead(pStrBlock, first_index, lWhich,
3867 nValue);
3868 }
3869 gstTextHighlightInfo.mode = PAINT_NORM;
3870 break;
3871
3872 case PAINT_NORM_INV_NORM:
3873 if (SameProperty(lWhich, nValue, pStrSeg, TRUE)) {
3874 /* nothing need to change */
3875 } else if (first_index == 0 && second_index == pStrSeg->dyn_str.sz-1) {
3876 changed = SetStrSegProperty(lWhich, nValue, pStrSeg);
3877 } else if (first_index == 0) {
3878 /* just change the head */
3879 changed = ChangeStrSegPropertyForHead(pStrBlock, second_index, lWhich,
3880 nValue);
3881 } else if (second_index == pStrSeg->dyn_str.sz-1) {
3882 /* just change the tail */
3883 changed = ChangeStrSegPropertyForTail(pStrBlock, first_index, lWhich,
3884 nValue);
3885 } else {
3886 /* change the middle */
3887 changed = ChangeStrSegPropertyForMiddle(pStrBlock, first_index,
3888 second_index, lWhich, nValue);
3889 }
3890 gstTextHighlightInfo.mode = PAINT_NORM;
3891 break;
3892 }
3893 return changed;
3894 }
3895
ChangeHighlightedTextProperty(lWhich,nValue)3896 int ChangeHighlightedTextProperty(lWhich, nValue)
3897 long lWhich;
3898 int nValue;
3899 /* returns TRUE if anything is changed */
3900 {
3901 MiniLineInfo *pOwnerMiniLine=NULL;
3902 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
3903 int first_index=0, second_index=0, mode=PAINT_NORM;
3904 int changed=FALSE;
3905
3906 /* setup gstTextHighlightInfo */
3907 if (!UpdateTextHighlightInfo()) return FALSE;
3908
3909 gstTextHighlightInfo.highlighting = FALSE;
3910 gstTextHighlightInfo.mode = PAINT_NORM;
3911
3912 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
3913 pOwnerMiniLine = pStrBlock->owner_mini_line;
3914
3915 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
3916 if (ChangePropertyForHighlightedTextInStrSeg(pStrBlock, mode, first_index,
3917 second_index, lWhich, nValue)) {
3918 changed = TRUE;
3919 }
3920 mode = gstTextHighlightInfo.mode;
3921 pStrBlock = pStrBlock->next;
3922 while (mode != PAINT_NORM) {
3923 if (pStrBlock == NULL) {
3924 pOwnerMiniLine = pOwnerMiniLine->next;
3925 if (pOwnerMiniLine == NULL) {
3926 break;
3927 }
3928 pStrBlock = pOwnerMiniLine->first_block;
3929 continue;
3930 }
3931 pNextStrBlock = pStrBlock->next;
3932 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
3933 if (mode == PAINT_INV) {
3934 if (SetStrBlockProperty(lWhich, nValue, pStrBlock)) {
3935 changed = TRUE;
3936 }
3937 } else {
3938 /* pStrBlock->type better be SB_SIMPLE */
3939 #ifdef _TGIF_DBG /* debug, do not translate */
3940 TgAssert(pStrBlock->type == SB_SIMPLE,
3941 "pStrBlock->type != SB_SIMPLE in ChangeHighlightedTextProperty()",
3942 NULL);
3943 #endif /* _TGIF_DBG */
3944 if (ChangePropertyForHighlightedTextInStrSeg(pStrBlock, mode,
3945 first_index, second_index, lWhich, nValue)) {
3946 changed = TRUE;
3947 }
3948 }
3949 mode = gstTextHighlightInfo.mode;
3950 pStrBlock = pNextStrBlock;
3951 }
3952 return changed;
3953 }
3954
3955 /* --------------------- OnePropertyMiniLines() --------------------- */
3956
3957 static
OnePropertyStrBlock(lWhich,nValue,pStrBlock,nCheckDoubleByte)3958 int OnePropertyStrBlock(lWhich, nValue, pStrBlock, nCheckDoubleByte)
3959 long lWhich;
3960 int nValue, nCheckDoubleByte;
3961 StrBlockInfo *pStrBlock;
3962 {
3963 switch (pStrBlock->type) {
3964 case SB_SIMPLE:
3965 return SameProperty(lWhich, nValue, pStrBlock->seg, nCheckDoubleByte);
3966
3967 case SB_CHAR_SPACE:
3968 break;
3969
3970 case SB_SUPSUB_LEFT:
3971 case SB_SUPSUB_CENTER:
3972 case SB_SUPSUB_RIGHT:
3973 if (pStrBlock->sup != NULL) {
3974 if (!OnePropertyMiniLines(lWhich, nValue, pStrBlock->sup,
3975 nCheckDoubleByte)) {
3976 return FALSE;
3977 }
3978 }
3979 if (pStrBlock->sub != NULL) {
3980 if (!OnePropertyMiniLines(lWhich, nValue, pStrBlock->sub,
3981 nCheckDoubleByte)) {
3982 return FALSE;
3983 }
3984 }
3985 if (pStrBlock->type == SB_SUPSUB_CENTER) {
3986 if (!SameProperty(lWhich, nValue, pStrBlock->seg, nCheckDoubleByte)) {
3987 return FALSE;
3988 }
3989 }
3990 break;
3991 }
3992 return TRUE;
3993 }
3994
3995 static
OnePropertyMiniLine(lWhich,nValue,pMiniLine,nCheckDoubleByte)3996 int OnePropertyMiniLine(lWhich, nValue, pMiniLine, nCheckDoubleByte)
3997 long lWhich;
3998 int nValue, nCheckDoubleByte;
3999 MiniLineInfo *pMiniLine;
4000 {
4001 StrBlockInfo *pStrBlock=NULL;
4002
4003 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
4004 pStrBlock=pStrBlock->next) {
4005 if (!OnePropertyStrBlock(lWhich, nValue, pStrBlock, nCheckDoubleByte)) {
4006 return FALSE;
4007 }
4008 }
4009 return TRUE;
4010 }
4011
OnePropertyMiniLines(lWhich,nValue,minilines,nCheckDoubleByte)4012 int OnePropertyMiniLines(lWhich, nValue, minilines, nCheckDoubleByte)
4013 long lWhich;
4014 int nValue, nCheckDoubleByte;
4015 MiniLinesInfo *minilines;
4016 {
4017 MiniLineInfo *pMiniLine=NULL;
4018
4019 for (pMiniLine=minilines->first; pMiniLine != NULL;
4020 pMiniLine=pMiniLine->next) {
4021 if (!OnePropertyMiniLine(lWhich, nValue, pMiniLine, nCheckDoubleByte)) {
4022 return FALSE;
4023 }
4024 }
4025 return TRUE;
4026 }
4027
4028 /* --------------------- SingleFontText() --------------------- */
4029
4030 static
SingleFontStrSeg(pStrSeg,pnSzUnit,pnDoubleByte,pnFont,pnStyle,pnUnderlineOn,pnOverlineOn)4031 int SingleFontStrSeg(pStrSeg, pnSzUnit, pnDoubleByte, pnFont, pnStyle,
4032 pnUnderlineOn, pnOverlineOn)
4033 StrSegInfo *pStrSeg;
4034 int *pnSzUnit, *pnDoubleByte, *pnFont, *pnStyle, *pnUnderlineOn;
4035 int *pnOverlineOn;
4036 {
4037 if (*pnDoubleByte == INVALID) {
4038 *pnSzUnit = pStrSeg->sz_unit;
4039 *pnDoubleByte = pStrSeg->double_byte;
4040 *pnFont = pStrSeg->font;
4041 *pnStyle = pStrSeg->style;
4042 *pnUnderlineOn = pStrSeg->underline_on;
4043 *pnOverlineOn = pStrSeg->overline_on;
4044 return TRUE;
4045 }
4046 return ((*pnSzUnit) == pStrSeg->sz_unit &&
4047 (*pnDoubleByte) == pStrSeg->double_byte &&
4048 (*pnFont) == pStrSeg->font &&
4049 (*pnStyle) == pStrSeg->style &&
4050 (*pnUnderlineOn) == pStrSeg->underline_on &&
4051 (*pnOverlineOn) == pStrSeg->overline_on);
4052 }
4053
4054 static
SingleFontStrBlock(pStrBlock,pnSzUnit,pnDoubleByte,pnFont,pnStyle,pnUnderlineOn,pnOverlineOn)4055 int SingleFontStrBlock(pStrBlock, pnSzUnit, pnDoubleByte, pnFont, pnStyle,
4056 pnUnderlineOn, pnOverlineOn)
4057 StrBlockInfo *pStrBlock;
4058 int *pnSzUnit, *pnDoubleByte, *pnFont, *pnStyle, *pnUnderlineOn;
4059 int *pnOverlineOn;
4060 {
4061 switch (pStrBlock->type) {
4062 case SB_SIMPLE:
4063 return SingleFontStrSeg(pStrBlock->seg, pnSzUnit, pnDoubleByte, pnFont,
4064 pnStyle, pnUnderlineOn, pnOverlineOn);
4065 break;
4066 case SB_CHAR_SPACE: return TRUE;
4067
4068 case SB_SUPSUB_LEFT:
4069 case SB_SUPSUB_CENTER:
4070 case SB_SUPSUB_RIGHT:
4071 if (pStrBlock->sup != NULL && !SingleFontMiniLines(pStrBlock->sup,
4072 pnSzUnit, pnDoubleByte, pnFont, pnStyle, pnUnderlineOn,
4073 pnOverlineOn)) {
4074 return FALSE;
4075 }
4076 if (pStrBlock->sub != NULL && !SingleFontMiniLines(pStrBlock->sub,
4077 pnSzUnit, pnDoubleByte, pnFont, pnStyle, pnUnderlineOn,
4078 pnOverlineOn)) {
4079 return FALSE;
4080 }
4081 if (pStrBlock->type == SB_SUPSUB_CENTER) {
4082 return SingleFontStrSeg(pStrBlock->seg, pnSzUnit, pnDoubleByte,
4083 pnFont, pnStyle, pnUnderlineOn, pnOverlineOn);
4084 }
4085 break;
4086 }
4087 return TRUE;
4088 }
4089
4090 static
SingleFontMiniLine(pMiniLine,pnSzUnit,pnDoubleByte,pnFont,pnStyle,pnUnderlineOn,pnOverlineOn)4091 int SingleFontMiniLine(pMiniLine, pnSzUnit, pnDoubleByte, pnFont, pnStyle,
4092 pnUnderlineOn, pnOverlineOn)
4093 MiniLineInfo *pMiniLine;
4094 int *pnSzUnit, *pnDoubleByte, *pnFont, *pnStyle, *pnUnderlineOn;
4095 int *pnOverlineOn;
4096 {
4097 StrBlockInfo *pStrBlock=NULL;
4098
4099 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
4100 pStrBlock=pStrBlock->next) {
4101 if (!SingleFontStrBlock(pStrBlock, pnSzUnit, pnDoubleByte, pnFont,
4102 pnStyle, pnUnderlineOn, pnOverlineOn)) {
4103 return FALSE;
4104 }
4105 }
4106 return TRUE;
4107 }
4108
SingleFontMiniLines(minilines,pnSzUnit,pnDoubleByte,pnFont,pnStyle,pnUnderlineOn,pnOverlineOn)4109 int SingleFontMiniLines(minilines, pnSzUnit, pnDoubleByte, pnFont, pnStyle,
4110 pnUnderlineOn, pnOverlineOn)
4111 MiniLinesInfo *minilines;
4112 int *pnSzUnit, *pnDoubleByte, *pnFont, *pnStyle, *pnUnderlineOn;
4113 int *pnOverlineOn;
4114 {
4115 MiniLineInfo *pMiniLine=NULL;
4116
4117 for (pMiniLine=minilines->first; pMiniLine != NULL;
4118 pMiniLine=pMiniLine->next) {
4119 if (!SingleFontMiniLine(pMiniLine, pnSzUnit, pnDoubleByte, pnFont,
4120 pnStyle, pnUnderlineOn, pnOverlineOn)) {
4121 return FALSE;
4122 }
4123 }
4124 return TRUE;
4125 }
4126
SingleFontText(text_ptr,pnSzUnit,pnDoubleByte,pnFont,pnStyle,pnUnderlineOn,pnOverlineOn)4127 int SingleFontText(text_ptr, pnSzUnit, pnDoubleByte, pnFont, pnStyle,
4128 pnUnderlineOn, pnOverlineOn)
4129 struct TextRec *text_ptr;
4130 int *pnSzUnit, *pnDoubleByte, *pnFont, *pnStyle, *pnUnderlineOn;
4131 int *pnOverlineOn;
4132 {
4133 MiniLinesInfo *minilines=(&text_ptr->minilines);
4134
4135 *pnDoubleByte = *pnFont = *pnStyle = INVALID;
4136 if (!SingleFontMiniLines(minilines, pnSzUnit, pnDoubleByte, pnFont,
4137 pnStyle, pnUnderlineOn, pnOverlineOn)) {
4138 return FALSE;
4139 }
4140 return ((*pnDoubleByte) != INVALID && (*pnFont) != INVALID &&
4141 (*pnStyle) != INVALID);
4142 }
4143
4144 /* --------------------- SingleColorText() --------------------- */
4145
4146 static
SingleColorStrSeg(pStrSeg,pnColorIndex)4147 int SingleColorStrSeg(pStrSeg, pnColorIndex)
4148 StrSegInfo *pStrSeg;
4149 int *pnColorIndex;
4150 {
4151 if (*pnColorIndex == INVALID) {
4152 *pnColorIndex = pStrSeg->color;
4153 return TRUE;
4154 }
4155 return ((*pnColorIndex) == pStrSeg->color);
4156 }
4157
4158 static
SingleColorStrBlock(pStrBlock,pnColorIndex)4159 int SingleColorStrBlock(pStrBlock, pnColorIndex)
4160 StrBlockInfo *pStrBlock;
4161 int *pnColorIndex;
4162 {
4163 switch (pStrBlock->type) {
4164 case SB_SIMPLE:
4165 return SingleColorStrSeg(pStrBlock->seg, pnColorIndex);
4166 break;
4167 case SB_CHAR_SPACE: return TRUE;
4168
4169 case SB_SUPSUB_LEFT:
4170 case SB_SUPSUB_CENTER:
4171 case SB_SUPSUB_RIGHT:
4172 if (pStrBlock->sup != NULL && !SingleColorMiniLines(pStrBlock->sup,
4173 pnColorIndex)) {
4174 return FALSE;
4175 }
4176 if (pStrBlock->sub != NULL && !SingleColorMiniLines(pStrBlock->sub,
4177 pnColorIndex)) {
4178 return FALSE;
4179 }
4180 if (pStrBlock->type == SB_SUPSUB_CENTER) {
4181 return SingleColorStrSeg(pStrBlock->seg, pnColorIndex);
4182 }
4183 break;
4184 }
4185 return TRUE;
4186 }
4187
4188 static
SingleColorMiniLine(pMiniLine,pnColorIndex)4189 int SingleColorMiniLine(pMiniLine, pnColorIndex)
4190 MiniLineInfo *pMiniLine;
4191 int *pnColorIndex;
4192 {
4193 StrBlockInfo *pStrBlock=NULL;
4194
4195 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
4196 pStrBlock=pStrBlock->next) {
4197 if (!SingleColorStrBlock(pStrBlock, pnColorIndex)) {
4198 return FALSE;
4199 }
4200 }
4201 return TRUE;
4202 }
4203
SingleColorMiniLines(minilines,pnColorIndex)4204 int SingleColorMiniLines(minilines, pnColorIndex)
4205 MiniLinesInfo *minilines;
4206 int *pnColorIndex;
4207 {
4208 MiniLineInfo *pMiniLine=NULL;
4209
4210 for (pMiniLine=minilines->first; pMiniLine != NULL;
4211 pMiniLine=pMiniLine->next) {
4212 if (!SingleColorMiniLine(pMiniLine, pnColorIndex)) {
4213 return FALSE;
4214 }
4215 }
4216 return TRUE;
4217 }
4218
SingleColorText(text_ptr,pnColorIndex)4219 int SingleColorText(text_ptr, pnColorIndex)
4220 struct TextRec *text_ptr;
4221 int *pnColorIndex;
4222 {
4223 MiniLinesInfo *minilines=(&text_ptr->minilines);
4224
4225 *pnColorIndex = INVALID;
4226 if (!SingleColorMiniLines(minilines, pnColorIndex)) {
4227 return FALSE;
4228 }
4229 return ((*pnColorIndex) != INVALID);
4230 }
4231
4232 /* -------------------- HighlightedTextHasSameProperty() -------------------- */
4233
4234 static
HighlightedStrSegHasSameProperty(pStrBlock,mode,lWhich,nValue,nCheckDoubleByte)4235 int HighlightedStrSegHasSameProperty(pStrBlock, mode, lWhich, nValue,
4236 nCheckDoubleByte)
4237 StrBlockInfo *pStrBlock;
4238 int mode, nValue, nCheckDoubleByte;
4239 long lWhich;
4240 {
4241 StrSegInfo *pStrSeg=pStrBlock->seg;
4242 int rc=TRUE;
4243
4244 if (mode == PAINT_NORM) return TRUE;
4245
4246 rc = SameProperty(lWhich, nValue, pStrSeg, nCheckDoubleByte);
4247
4248 switch (mode) {
4249 case PAINT_INV: break;
4250 case PAINT_NORM_INV: gstTextHighlightInfo.mode = PAINT_INV; break;
4251 case PAINT_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4252 case PAINT_NORM_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4253 }
4254 return rc;
4255 }
4256
HighlightedTextHasSameProperty(lWhich,nValue,nCheckDoubleByte)4257 int HighlightedTextHasSameProperty(lWhich, nValue, nCheckDoubleByte)
4258 long lWhich;
4259 int nValue, nCheckDoubleByte;
4260 /* returns TRUE if anything is changed */
4261 {
4262 MiniLineInfo *pOwnerMiniLine=NULL;
4263 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
4264 int first_index=0, second_index=0, mode=PAINT_NORM;
4265
4266 /* setup gstTextHighlightInfo */
4267 if (!UpdateTextHighlightInfo()) return FALSE;
4268
4269 gstTextHighlightInfo.highlighting = FALSE;
4270 gstTextHighlightInfo.mode = PAINT_NORM;
4271
4272 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
4273 pOwnerMiniLine = pStrBlock->owner_mini_line;
4274
4275 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4276 if (!HighlightedStrSegHasSameProperty(pStrBlock, mode, lWhich, nValue,
4277 nCheckDoubleByte)) {
4278 return FALSE;
4279 }
4280 mode = gstTextHighlightInfo.mode;
4281 pStrBlock = pStrBlock->next;
4282 while (mode != PAINT_NORM) {
4283 if (pStrBlock == NULL) {
4284 pOwnerMiniLine = pOwnerMiniLine->next;
4285 if (pOwnerMiniLine == NULL) {
4286 break;
4287 }
4288 pStrBlock = pOwnerMiniLine->first_block;
4289 continue;
4290 }
4291 pNextStrBlock = pStrBlock->next;
4292 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4293 if (mode == PAINT_INV) {
4294 if (!OnePropertyStrBlock(lWhich, nValue, pStrBlock,
4295 nCheckDoubleByte)) {
4296 return FALSE;
4297 }
4298 } else {
4299 /* pStrBlock->type better be SB_SIMPLE */
4300 #ifdef _TGIF_DBG /* debug, do not translate */
4301 TgAssert(pStrBlock->type == SB_SIMPLE,
4302 "pStrBlock->type != SB_SIMPLE in HighlightedTextHasSameProperty()",
4303 NULL);
4304 #endif /* _TGIF_DBG */
4305 if (!HighlightedStrSegHasSameProperty(pStrBlock, mode, lWhich,
4306 nValue, nCheckDoubleByte)) {
4307 return FALSE;
4308 }
4309 }
4310 mode = gstTextHighlightInfo.mode;
4311 pStrBlock = pNextStrBlock;
4312 }
4313 return TRUE;
4314 }
4315
4316 /* --------------------- CheckMiniLinesProperties() --------------------- */
4317
4318 static
CheckStrSegProperties(pStrSeg,pn_valid,pn_font,pn_style,pn_sz_unit,pn_color,pn_underline_on,pn_overline_on)4319 int CheckStrSegProperties(pStrSeg, pn_valid, pn_font, pn_style, pn_sz_unit,
4320 pn_color, pn_underline_on, pn_overline_on)
4321 StrSegInfo *pStrSeg;
4322 int *pn_valid, *pn_font, *pn_style, *pn_sz_unit, *pn_color, *pn_underline_on;
4323 int *pn_overline_on;
4324 /* return FALSE if any property is different */
4325 {
4326 if (*pn_valid) {
4327 return (*pn_font == pStrSeg->font &&
4328 *pn_style == pStrSeg->style &&
4329 *pn_sz_unit == pStrSeg->sz_unit &&
4330 *pn_color == pStrSeg->color &&
4331 *pn_underline_on == pStrSeg->underline_on &&
4332 *pn_overline_on == pStrSeg->overline_on);
4333 } else {
4334 *pn_valid = TRUE;
4335 *pn_font = pStrSeg->font;
4336 *pn_style = pStrSeg->style;
4337 *pn_sz_unit = pStrSeg->sz_unit;
4338 *pn_color = pStrSeg->color;
4339 *pn_underline_on = pStrSeg->underline_on;
4340 *pn_overline_on = pStrSeg->overline_on;
4341 }
4342 return TRUE;
4343 }
4344
4345 static
CheckStrBlockProperties(pStrBlock,pn_valid,pn_font,pn_style,pn_sz_unit,pn_color,pn_underline_on,pn_overline_on)4346 int CheckStrBlockProperties(pStrBlock, pn_valid, pn_font, pn_style,
4347 pn_sz_unit, pn_color, pn_underline_on, pn_overline_on)
4348 StrBlockInfo *pStrBlock;
4349 int *pn_valid, *pn_font, *pn_style, *pn_sz_unit, *pn_color, *pn_underline_on;
4350 int *pn_overline_on;
4351 /* return FALSE if any property is different */
4352 {
4353 switch (pStrBlock->type) {
4354 case SB_SIMPLE:
4355 return CheckStrSegProperties(pStrBlock->seg, pn_valid, pn_font,
4356 pn_style, pn_sz_unit, pn_color, pn_underline_on, pn_overline_on);
4357
4358 case SB_CHAR_SPACE:
4359 break;
4360
4361 case SB_SUPSUB_LEFT:
4362 case SB_SUPSUB_CENTER:
4363 case SB_SUPSUB_RIGHT:
4364 if (pStrBlock->sup != NULL) {
4365 if (!CheckMiniLinesProperties(pStrBlock->sup, pn_valid, pn_font,
4366 pn_style, pn_sz_unit, pn_color, pn_underline_on,
4367 pn_overline_on)) {
4368 return FALSE;
4369 }
4370 }
4371 if (pStrBlock->sub != NULL) {
4372 if (!CheckMiniLinesProperties(pStrBlock->sub, pn_valid, pn_font,
4373 pn_style, pn_sz_unit, pn_color, pn_underline_on,
4374 pn_overline_on)) {
4375 return FALSE;
4376 }
4377 }
4378 if (pStrBlock->type == SB_SUPSUB_CENTER) {
4379 if (!CheckStrSegProperties(pStrBlock->seg, pn_valid, pn_font,
4380 pn_style, pn_sz_unit, pn_color, pn_underline_on,
4381 pn_overline_on)) {
4382 return FALSE;
4383 }
4384 }
4385 break;
4386 }
4387 return TRUE;
4388 }
4389
4390 static
CheckMiniLineProperties(pMiniLine,pn_valid,pn_font,pn_style,pn_sz_unit,pn_color,pn_underline_on,pn_overline_on)4391 int CheckMiniLineProperties(pMiniLine, pn_valid, pn_font, pn_style,
4392 pn_sz_unit, pn_color, pn_underline_on, pn_overline_on)
4393 MiniLineInfo *pMiniLine;
4394 int *pn_valid, *pn_font, *pn_style, *pn_sz_unit, *pn_color, *pn_underline_on;
4395 int *pn_overline_on;
4396 /* return FALSE if any property is different */
4397 {
4398 StrBlockInfo *pStrBlock=NULL;
4399
4400 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
4401 pStrBlock=pStrBlock->next) {
4402 if (!CheckStrBlockProperties(pStrBlock, pn_valid, pn_font, pn_style,
4403 pn_sz_unit, pn_color, pn_underline_on, pn_overline_on)) {
4404 return FALSE;
4405 }
4406 }
4407 return TRUE;
4408 }
4409
CheckMiniLinesProperties(minilines,pn_valid,pn_font,pn_style,pn_sz_unit,pn_color,pn_underline_on,pn_overline_on)4410 int CheckMiniLinesProperties(minilines, pn_valid, pn_font, pn_style,
4411 pn_sz_unit, pn_color, pn_underline_on, pn_overline_on)
4412 MiniLinesInfo *minilines;
4413 int *pn_valid, *pn_font, *pn_style, *pn_sz_unit, *pn_color, *pn_underline_on;
4414 int *pn_overline_on;
4415 /* return FALSE if any property is different */
4416 {
4417 MiniLineInfo *pMiniLine=NULL;
4418
4419 for (pMiniLine=minilines->first; pMiniLine != NULL;
4420 pMiniLine=pMiniLine->next) {
4421 if (!CheckMiniLineProperties(pMiniLine, pn_valid, pn_font, pn_style,
4422 pn_sz_unit, pn_color, pn_underline_on, pn_overline_on)) {
4423 return FALSE;
4424 }
4425 }
4426 return TRUE;
4427 }
4428
4429 /* ------------------- CanCopyHighLightedTextAsStrings() ------------------- */
4430
4431 static
CheckHighlightedStrSegProperties(pStrBlock,mode,pn_valid,pn_font,pn_style,pn_sz_unit,pn_color,pn_underline_on,pn_overline_on)4432 int CheckHighlightedStrSegProperties(pStrBlock, mode, pn_valid, pn_font,
4433 pn_style, pn_sz_unit, pn_color, pn_underline_on, pn_overline_on)
4434 StrBlockInfo *pStrBlock;
4435 int mode, *pn_valid, *pn_font, *pn_style, *pn_sz_unit, *pn_color;
4436 int *pn_underline_on, *pn_overline_on;
4437 /* return FALSE if any property is different */
4438 {
4439 StrSegInfo *pStrSeg=pStrBlock->seg;
4440 int rc=TRUE;
4441
4442 if (mode == PAINT_NORM) return TRUE;
4443
4444 rc = CheckStrSegProperties(pStrSeg, pn_valid, pn_font, pn_style, pn_sz_unit,
4445 pn_color, pn_underline_on, pn_overline_on);
4446 switch (mode) {
4447 case PAINT_INV: break;
4448 case PAINT_NORM_INV: gstTextHighlightInfo.mode = PAINT_INV; break;
4449 case PAINT_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4450 case PAINT_NORM_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4451 }
4452 return rc;
4453 }
4454
CanCopyHighLightedTextAsStrings()4455 int CanCopyHighLightedTextAsStrings()
4456 /* returns TRUE if highlighted text is to be copied as simple text */
4457 /* if the font is a double-byte font, don't treat it like a simple text */
4458 {
4459 MiniLineInfo *pOwnerMiniLine=NULL;
4460 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
4461 int first_index=0, second_index=0, mode=PAINT_NORM, valid=FALSE;
4462 int font=INVALID, style=INVALID, sz_unit=INVALID, color=INVALID;
4463 int underline_on=INVALID, overline_on=INVALID;
4464
4465 /* setup gstTextHighlightInfo */
4466 if (!UpdateTextHighlightInfo()) return FALSE;
4467
4468 gstTextHighlightInfo.highlighting = FALSE;
4469 gstTextHighlightInfo.mode = PAINT_NORM;
4470
4471 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
4472 pOwnerMiniLine = pStrBlock->owner_mini_line;
4473
4474 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4475 if (!CheckHighlightedStrSegProperties(pStrBlock, mode, &valid, &font, &style,
4476 &sz_unit, &color, &underline_on, &overline_on)) {
4477 return FALSE;
4478 }
4479 if (valid && IsFontDoubleByte(font)) {
4480 return FALSE;
4481 }
4482 mode = gstTextHighlightInfo.mode;
4483 pStrBlock = pStrBlock->next;
4484 while (mode != PAINT_NORM) {
4485 if (pStrBlock == NULL) {
4486 pOwnerMiniLine = pOwnerMiniLine->next;
4487 if (pOwnerMiniLine == NULL) {
4488 break;
4489 }
4490 pStrBlock = pOwnerMiniLine->first_block;
4491 continue;
4492 }
4493 pNextStrBlock = pStrBlock->next;
4494 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4495 if (mode == PAINT_INV) {
4496 if (pStrBlock->type == SB_SIMPLE) {
4497 if (!CheckStrBlockProperties(pStrBlock, &valid, &font, &style,
4498 &sz_unit, &color, &underline_on, &overline_on)) {
4499 return FALSE;
4500 }
4501 if (valid && IsFontDoubleByte(font)) {
4502 return FALSE;
4503 }
4504 } else {
4505 return FALSE;
4506 }
4507 } else {
4508 /* pStrBlock->type better be SB_SIMPLE */
4509 #ifdef _TGIF_DBG /* debug, do not translate */
4510 TgAssert(pStrBlock->type == SB_SIMPLE,
4511 "pStrBlock->type != SB_SIMPLE in CanCopyHighLightedTextAsStrings()",
4512 NULL);
4513 #endif /* _TGIF_DBG */
4514 if (!CheckHighlightedStrSegProperties(pStrBlock, mode, &valid, &font,
4515 &style, &sz_unit, &color, &underline_on, &overline_on)) {
4516 return FALSE;
4517 }
4518 if (valid && IsFontDoubleByte(font)) {
4519 return FALSE;
4520 }
4521 }
4522 mode = gstTextHighlightInfo.mode;
4523 pStrBlock = pNextStrBlock;
4524 }
4525 return TRUE;
4526 }
4527
4528 /* ----------------- CanCopyHighLightedTextAsUTF8Strings() ----------------- */
4529
4530 static
CheckHighlightedStrSegPropertiesForCopyHighLightedTextAsUTF8Strings(mode)4531 void CheckHighlightedStrSegPropertiesForCopyHighLightedTextAsUTF8Strings(mode)
4532 int mode;
4533 {
4534 if (mode == PAINT_NORM) return;
4535
4536 switch (mode) {
4537 case PAINT_INV: break;
4538 case PAINT_NORM_INV: gstTextHighlightInfo.mode = PAINT_INV; break;
4539 case PAINT_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4540 case PAINT_NORM_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4541 }
4542 }
4543
4544 static
CheckDoubleByteFontForCopyHighLightedTextAsUTF8Strings(mode,pStrSeg,pn_double_byte_font,pn_valid)4545 int CheckDoubleByteFontForCopyHighLightedTextAsUTF8Strings(mode, pStrSeg,
4546 pn_double_byte_font, pn_valid)
4547 int mode, *pn_double_byte_font, *pn_valid;
4548 StrSegInfo *pStrSeg;
4549 {
4550 int font_index=pStrSeg->font;
4551
4552 if (mode == PAINT_NORM) return TRUE;
4553
4554 if (IsFontDoubleByte(font_index)) {
4555 if (CanConvertUTF8ToFont(font_index)) {
4556 if (*pn_valid) {
4557 if (*pn_double_byte_font != font_index) {
4558 return FALSE;
4559 }
4560 } else {
4561 *pn_double_byte_font = font_index;
4562 *pn_valid = TRUE;
4563 SetCopyUTF8FontInfo(pStrSeg, TRUE);
4564 }
4565 } else {
4566 return FALSE;
4567 }
4568 } else {
4569 if (!gstCopyUTF8Info.single_byte_valid) {
4570 SetCopyUTF8FontInfo(pStrSeg, FALSE);
4571 }
4572 }
4573 switch (mode) {
4574 case PAINT_INV: break;
4575 case PAINT_NORM_INV: gstTextHighlightInfo.mode = PAINT_INV; break;
4576 case PAINT_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4577 case PAINT_NORM_INV_NORM: gstTextHighlightInfo.mode = PAINT_NORM; break;
4578 }
4579 return TRUE;
4580 }
4581
CanCopyHighLightedTextAsUTF8Strings(pn_double_byte_font_index)4582 int CanCopyHighLightedTextAsUTF8Strings(pn_double_byte_font_index)
4583 int *pn_double_byte_font_index;
4584 /* returns TRUE if highlighted text is to be copied as simple text */
4585 /* if the font is a double-byte font, don't treat it like a simple text */
4586 {
4587 MiniLineInfo *pOwnerMiniLine=NULL;
4588 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
4589 int first_index=0, second_index=0, mode=PAINT_NORM, valid=FALSE;
4590 int double_byte_font=INVALID;
4591
4592 /* setup gstTextHighlightInfo */
4593 if (!UpdateTextHighlightInfo()) return FALSE;
4594 ClearCopyUTF8Info();
4595
4596 gstTextHighlightInfo.highlighting = FALSE;
4597 gstTextHighlightInfo.mode = PAINT_NORM;
4598
4599 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
4600 pOwnerMiniLine = pStrBlock->owner_mini_line;
4601
4602 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4603
4604 CheckHighlightedStrSegPropertiesForCopyHighLightedTextAsUTF8Strings(mode);
4605 if (IsFontDoubleByte(pStrBlock->seg->font)) {
4606 if (CanConvertUTF8ToFont(pStrBlock->seg->font)) {
4607 double_byte_font = pStrBlock->seg->font;
4608 valid = TRUE;
4609 SetCopyUTF8FontInfo(pStrBlock->seg, TRUE);
4610 } else {
4611 return FALSE;
4612 }
4613 } else {
4614 SetCopyUTF8FontInfo(pStrBlock->seg, FALSE);
4615 }
4616 mode = gstTextHighlightInfo.mode;
4617 pStrBlock = pStrBlock->next;
4618 while (mode != PAINT_NORM) {
4619 if (pStrBlock == NULL) {
4620 pOwnerMiniLine = pOwnerMiniLine->next;
4621 if (pOwnerMiniLine == NULL) {
4622 break;
4623 }
4624 pStrBlock = pOwnerMiniLine->first_block;
4625 continue;
4626 }
4627 pNextStrBlock = pStrBlock->next;
4628 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4629 if (mode == PAINT_INV) {
4630 if (pStrBlock->type == SB_SIMPLE) {
4631 if (!CheckDoubleByteFontForCopyHighLightedTextAsUTF8Strings(
4632 mode, pStrBlock->seg, &double_byte_font, &valid)) {
4633 return FALSE;
4634 }
4635 } else {
4636 return FALSE;
4637 }
4638 } else {
4639 /* pStrBlock->type better be SB_SIMPLE */
4640 #ifdef _TGIF_DBG /* debug, do not translate */
4641 TgAssert(pStrBlock->type == SB_SIMPLE,
4642 "pStrBlock->type != SB_SIMPLE in CanCopyHighLightedTextAsUTF8Strings()",
4643 NULL);
4644 #endif /* _TGIF_DBG */
4645 if (!CheckDoubleByteFontForCopyHighLightedTextAsUTF8Strings(
4646 mode, pStrBlock->seg, &double_byte_font, &valid)) {
4647 return FALSE;
4648 }
4649 }
4650 mode = gstTextHighlightInfo.mode;
4651 pStrBlock = pNextStrBlock;
4652 }
4653 if (valid && pn_double_byte_font_index != NULL) {
4654 *pn_double_byte_font_index = double_byte_font;
4655 }
4656 if (valid) {
4657 DebugCopyUTF8Info();
4658 }
4659 return valid;
4660 }
4661
4662 /* ----------------- CanPasteUTF8StringIntoText() ----------------- */
4663
CanPasteUTF8StringIntoText(pssi)4664 int CanPasteUTF8StringIntoText(pssi)
4665 StrSegInfo *pssi;
4666 /* returns TRUE if highlighted text is to be copied as simple text */
4667 /* if the font is a double-byte font, don't treat it like a simple text */
4668 {
4669 StrBlockInfo *pStrBlock=NULL;
4670
4671 if (!textHighlight) {
4672 if (CanConvertUTF8ToFont(curFont)) {
4673 return TRUE;
4674 }
4675 if (CanFindDoubleByteFontAtCursor(pssi)) {
4676 return CanConvertUTF8ToFont(pssi->font);
4677 }
4678 return FALSE;
4679 }
4680 /* setup gstTextHighlightInfo */
4681 if (!UpdateTextHighlightInfo()) return FALSE;
4682
4683 if (FixHighlightedStrBlockDepths() < 0) {
4684 SwitchTextCurAndEndStrBlocks();
4685 }
4686 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
4687 if (pStrBlock->seg->double_byte) {
4688 return TRUE;
4689 }
4690 if (CanFindDoubleByteFontAtCursor(pssi)) {
4691 return CanConvertUTF8ToFont(pssi->font);
4692 }
4693 return FALSE;
4694 }
4695
4696 /* -------------------- GatherHighLightedTextAsStrings() -------------------- */
4697
4698 static
GatherString(buf,len,ppsz_buf,pn_buf_sz)4699 void GatherString(buf, len, ppsz_buf, pn_buf_sz)
4700 char *buf, **ppsz_buf;
4701 int len, *pn_buf_sz;
4702 /* *pn_buf_sz includes the terminating '\0' */
4703 {
4704 if (*ppsz_buf == NULL) {
4705 *ppsz_buf = (char*)malloc(len+1);
4706 if (*ppsz_buf == NULL) FailAllocMessage();
4707 memcpy(*ppsz_buf, buf, len+1);
4708 *pn_buf_sz = len+1;
4709 } else {
4710 *ppsz_buf = (char*)realloc(*ppsz_buf, (*pn_buf_sz)+len);
4711 if (*ppsz_buf == NULL) FailAllocMessage();
4712 memcpy(&(*ppsz_buf)[*pn_buf_sz-1], buf, len+1);
4713 *pn_buf_sz += len;
4714 }
4715 }
4716
4717 static
GatherStrSeg(pStrSeg,ppsz_buf,pn_buf_sz)4718 void GatherStrSeg(pStrSeg, ppsz_buf, pn_buf_sz)
4719 StrSegInfo *pStrSeg;
4720 char **ppsz_buf;
4721 int *pn_buf_sz;
4722 /* *pn_buf_sz includes the terminating '\0' */
4723 {
4724 GatherString(pStrSeg->dyn_str.s, pStrSeg->dyn_str.sz-1, ppsz_buf, pn_buf_sz);
4725 }
4726
4727 static
GatherHighlightedStrSeg(pStrBlock,mode,first_index,second_index,ppsz_buf,pn_buf_sz)4728 void GatherHighlightedStrSeg(pStrBlock, mode, first_index, second_index,
4729 ppsz_buf, pn_buf_sz)
4730 StrBlockInfo *pStrBlock;
4731 int mode, first_index, second_index, *pn_buf_sz;
4732 char **ppsz_buf;
4733 {
4734 StrSegInfo *pStrSeg=pStrBlock->seg;
4735 char *buf=NULL, saved_ch='\0';
4736 int len=0;
4737
4738 if (mode == PAINT_NORM) return;
4739
4740 switch (mode) {
4741 case PAINT_INV:
4742 /* can only get here if pStrBlock->type is SB_SIMPLE */
4743 GatherStrSeg(pStrSeg, ppsz_buf, pn_buf_sz);
4744 break;
4745
4746 case PAINT_NORM_INV:
4747 /* gathering the tail */
4748 if (first_index == pStrSeg->dyn_str.sz-1) {
4749 /* nothing need to change */
4750 } else {
4751 buf = (&pStrSeg->dyn_str.s[first_index]);
4752 len = pStrSeg->dyn_str.sz-1-first_index;
4753 GatherString(buf, len, ppsz_buf, pn_buf_sz);
4754 }
4755 gstTextHighlightInfo.mode = PAINT_INV;
4756 break;
4757
4758 case PAINT_INV_NORM:
4759 /* gathering the head */
4760 if (first_index == 0) {
4761 /* nothing need to change */
4762 } else {
4763 buf = pStrSeg->dyn_str.s;
4764 saved_ch = buf[first_index];
4765
4766 buf[first_index] = '\0';
4767 GatherString(buf, first_index, ppsz_buf, pn_buf_sz);
4768 buf[first_index] = saved_ch;
4769 }
4770 gstTextHighlightInfo.mode = PAINT_NORM;
4771 break;
4772
4773 case PAINT_NORM_INV_NORM:
4774 if (first_index == 0 && second_index == pStrSeg->dyn_str.sz-1) {
4775 GatherStrSeg(pStrSeg, ppsz_buf, pn_buf_sz);
4776 } else if (first_index == 0) {
4777 /* just change the head */
4778 buf = pStrSeg->dyn_str.s;
4779 saved_ch = buf[second_index];
4780
4781 buf[second_index] = '\0';
4782 GatherString(buf, second_index, ppsz_buf, pn_buf_sz);
4783 buf[second_index] = saved_ch;
4784 } else if (second_index == pStrSeg->dyn_str.sz-1) {
4785 /* just change the tail */
4786 buf = (&pStrSeg->dyn_str.s[first_index]);
4787 len = pStrSeg->dyn_str.sz-1-first_index;
4788 GatherString(buf, len, ppsz_buf, pn_buf_sz);
4789 } else {
4790 /* change the middle */
4791 buf = pStrSeg->dyn_str.s;
4792 saved_ch = buf[second_index];
4793
4794 buf[second_index] = '\0';
4795 GatherString(&buf[first_index], second_index-first_index,
4796 ppsz_buf, pn_buf_sz);
4797 buf[second_index] = saved_ch;
4798 }
4799 gstTextHighlightInfo.mode = PAINT_NORM;
4800 break;
4801 }
4802 }
4803
GatherHighLightedTextAsStrings(ppsz_buf,pn_buf_sz)4804 void GatherHighLightedTextAsStrings(ppsz_buf, pn_buf_sz)
4805 char **ppsz_buf;
4806 int *pn_buf_sz;
4807 /* *pn_buf_sz will include the terminating '\0' */
4808 {
4809 MiniLineInfo *pOwnerMiniLine=NULL;
4810 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
4811 int first_index=0, second_index=0, mode=PAINT_NORM;
4812
4813 /* setup gstTextHighlightInfo */
4814 if (!UpdateTextHighlightInfo()) return;
4815
4816 gstTextHighlightInfo.highlighting = FALSE;
4817 gstTextHighlightInfo.mode = PAINT_NORM;
4818
4819 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
4820 pOwnerMiniLine = pStrBlock->owner_mini_line;
4821
4822 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4823 GatherHighlightedStrSeg(pStrBlock, mode, first_index, second_index,
4824 ppsz_buf, pn_buf_sz);
4825 mode = gstTextHighlightInfo.mode;
4826 pStrBlock = pStrBlock->next;
4827 while (mode != PAINT_NORM) {
4828 if (pStrBlock == NULL) {
4829 pOwnerMiniLine = pOwnerMiniLine->next;
4830 if (pOwnerMiniLine == NULL) {
4831 break;
4832 }
4833 pStrBlock = pOwnerMiniLine->first_block;
4834 GatherString("\n", 1, ppsz_buf, pn_buf_sz);
4835 continue;
4836 }
4837 pNextStrBlock = pStrBlock->next;
4838 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4839
4840 /* pStrBlock->type better be SB_SIMPLE */
4841 #ifdef _TGIF_DBG /* debug, do not translate */
4842 TgAssert(pStrBlock->type == SB_SIMPLE,
4843 "pStrBlock->type != SB_SIMPLE in GatherHighLightedTextAsStrings()",
4844 NULL);
4845 #endif /* _TGIF_DBG */
4846 if (mode == PAINT_INV) {
4847 GatherStrSeg(pStrBlock->seg, ppsz_buf, pn_buf_sz);
4848 } else {
4849 GatherHighlightedStrSeg(pStrBlock, mode, first_index, second_index,
4850 ppsz_buf, pn_buf_sz);
4851 }
4852 mode = gstTextHighlightInfo.mode;
4853 pStrBlock = pNextStrBlock;
4854 }
4855 }
4856
4857 /* ------------------- CreateTextObjFromHighLightedText() ------------------- */
4858
4859 static
CopyHighlightedStrSeg(pStrBlock,mode,first_index,second_index,pNewOwnerMiniLine)4860 void CopyHighlightedStrSeg(pStrBlock, mode, first_index,
4861 second_index, pNewOwnerMiniLine)
4862 StrBlockInfo *pStrBlock;
4863 int mode, first_index, second_index;
4864 MiniLineInfo *pNewOwnerMiniLine; /* owner miniline of the new string block */
4865 {
4866 StrSegInfo *pStrSeg=pStrBlock->seg;
4867 char *buf=NULL;
4868 int faked_simple_type=FALSE;
4869
4870 if (pStrBlock->type == SB_SUPSUB_CENTER) {
4871 /* only coping the string segment */
4872 faked_simple_type = TRUE;
4873 pStrBlock->type = SB_SIMPLE;
4874 }
4875 switch (mode) {
4876 case PAINT_NORM: break;
4877
4878 case PAINT_INV:
4879 DupStrBlock(pStrBlock, pNewOwnerMiniLine, &pNewOwnerMiniLine->first_block,
4880 &pNewOwnerMiniLine->last_block);
4881 break;
4882
4883 case PAINT_NORM_INV:
4884 /* copying the tail */
4885 buf = (&pStrSeg->dyn_str.s[first_index]);
4886 DupStrBlock(pStrBlock, pNewOwnerMiniLine,
4887 &pNewOwnerMiniLine->first_block, &pNewOwnerMiniLine->last_block);
4888 DynStrSet(&pNewOwnerMiniLine->last_block->seg->dyn_str, buf);
4889 gstTextHighlightInfo.mode = PAINT_INV;
4890 break;
4891
4892 case PAINT_INV_NORM:
4893 /* copying the head */
4894 if (first_index == 0) {
4895 /* nothing to copy */
4896 } else {
4897 char saved_ch='\0';
4898
4899 buf = pStrSeg->dyn_str.s;
4900 saved_ch = buf[first_index];
4901 buf[first_index] = '\0';
4902 DupStrBlock(pStrBlock, pNewOwnerMiniLine,
4903 &pNewOwnerMiniLine->first_block, &pNewOwnerMiniLine->last_block);
4904 DynStrSet(&pNewOwnerMiniLine->last_block->seg->dyn_str, buf);
4905 buf[first_index] = saved_ch;
4906 }
4907 gstTextHighlightInfo.mode = PAINT_NORM;
4908 break;
4909
4910 case PAINT_NORM_INV_NORM:
4911 if (first_index == 0 && second_index == pStrSeg->dyn_str.sz-1) {
4912 DupStrBlock(pStrBlock, pNewOwnerMiniLine,
4913 &pNewOwnerMiniLine->first_block, &pNewOwnerMiniLine->last_block);
4914 } else if (first_index == 0) {
4915 /* just copy the head */
4916 char saved_ch='\0';
4917
4918 buf = pStrSeg->dyn_str.s;
4919 saved_ch = buf[second_index];
4920 buf[second_index] = '\0';
4921 DupStrBlock(pStrBlock, pNewOwnerMiniLine,
4922 &pNewOwnerMiniLine->first_block, &pNewOwnerMiniLine->last_block);
4923 DynStrSet(&pNewOwnerMiniLine->last_block->seg->dyn_str, buf);
4924 buf[second_index] = saved_ch;
4925 } else if (second_index == pStrSeg->dyn_str.sz-1) {
4926 /* just copy the tail */
4927 buf = (&pStrSeg->dyn_str.s[first_index]);
4928 DupStrBlock(pStrBlock, pNewOwnerMiniLine,
4929 &pNewOwnerMiniLine->first_block, &pNewOwnerMiniLine->last_block);
4930 DynStrSet(&pNewOwnerMiniLine->last_block->seg->dyn_str, buf);
4931 } else {
4932 /* change the middle */
4933 char saved_ch='\0';
4934
4935 buf = pStrSeg->dyn_str.s;
4936 saved_ch = buf[second_index];
4937 buf[second_index] = '\0';
4938 DupStrBlock(pStrBlock, pNewOwnerMiniLine,
4939 &pNewOwnerMiniLine->first_block, &pNewOwnerMiniLine->last_block);
4940 DynStrSet(&pNewOwnerMiniLine->last_block->seg->dyn_str,
4941 &buf[first_index]);
4942 buf[second_index] = saved_ch;
4943 }
4944 gstTextHighlightInfo.mode = PAINT_NORM;
4945 break;
4946 }
4947 if (faked_simple_type) {
4948 pStrBlock->type = SB_SUPSUB_CENTER;
4949 }
4950 }
4951
CreateTextObjFromHighLightedText()4952 struct ObjRec *CreateTextObjFromHighLightedText()
4953 {
4954 MiniLinesInfo *minilines=NULL;
4955 MiniLineInfo *pOwnerMiniLine=NULL, *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
4956 StrBlockInfo *pStrBlock=NULL, *pNextStrBlock=NULL;
4957 int first_index=0, second_index=0, mode=PAINT_NORM, num_lines=1;
4958 struct ObjRec *partial_text_obj_ptr=NULL;
4959 struct TextRec *text_ptr=NULL;
4960
4961 /* setup gstTextHighlightInfo */
4962 if (!UpdateTextHighlightInfo()) return NULL;
4963
4964 partial_text_obj_ptr = DupObj(curTextObj);
4965 if (partial_text_obj_ptr == NULL) return NULL;
4966 text_ptr = partial_text_obj_ptr->detail.t;
4967 minilines = (&text_ptr->minilines);
4968 FreeMiniLines(minilines, FALSE);
4969 InvalidateTextCache(text_ptr);
4970 pFirstMiniLine = pLastMiniLine = NewMiniLine();
4971 pLastMiniLine->owner_minilines = minilines;
4972
4973 gstTextHighlightInfo.highlighting = FALSE;
4974 gstTextHighlightInfo.mode = PAINT_NORM;
4975
4976 pStrBlock = gstTextHighlightInfo.start_str_block_ptr;
4977 pOwnerMiniLine = pStrBlock->owner_mini_line;
4978
4979 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
4980 CopyHighlightedStrSeg(pStrBlock, mode, first_index, second_index,
4981 pLastMiniLine);
4982 mode = gstTextHighlightInfo.mode;
4983 pStrBlock = pStrBlock->next;
4984 while (mode != PAINT_NORM) {
4985 if (pStrBlock == NULL) {
4986 MiniLineInfo *pNewMiniLine=NULL;
4987
4988 pOwnerMiniLine = pOwnerMiniLine->next;
4989 if (pOwnerMiniLine == NULL) {
4990 break;
4991 }
4992 pStrBlock = pOwnerMiniLine->first_block;
4993 pNewMiniLine = NewMiniLine();
4994 pNewMiniLine->owner_minilines = minilines;
4995 num_lines++;
4996 InsertMiniLine(pLastMiniLine, NULL, pNewMiniLine, &pFirstMiniLine,
4997 &pLastMiniLine);
4998 continue;
4999 }
5000 pNextStrBlock = pStrBlock->next;
5001 GetPaintMode(pStrBlock, &mode, &first_index, &second_index);
5002 if (mode == PAINT_INV) {
5003 DupStrBlock(pStrBlock, pLastMiniLine, &pLastMiniLine->first_block,
5004 &pLastMiniLine->last_block);
5005 } else {
5006 /* pStrBlock->type better be SB_SIMPLE */
5007 #ifdef _TGIF_DBG /* debug, do not translate */
5008 TgAssert(pStrBlock->type == SB_SIMPLE,
5009 "pStrBlock->type != SB_SIMPLE in CreateTextObjFromHighLightedText()",
5010 NULL);
5011 #endif /* _TGIF_DBG */
5012 CopyHighlightedStrSeg(pStrBlock, mode, first_index, second_index,
5013 pLastMiniLine);
5014 }
5015 mode = gstTextHighlightInfo.mode;
5016 pStrBlock = pNextStrBlock;
5017 }
5018 minilines->first = pFirstMiniLine;
5019 minilines->last = pLastMiniLine;
5020 text_ptr->lines = num_lines;
5021 text_ptr->baseline_y = curTextObj->detail.t->baseline_y;
5022 RecalcTextMetrics(text_ptr, partial_text_obj_ptr->x, text_ptr->baseline_y);
5023 UpdTextBBox(partial_text_obj_ptr);
5024 return partial_text_obj_ptr;
5025 }
5026
5027 /* --------------------- ReorderCursorStrBlocks() --------------------- */
5028
ReorderCursorStrBlocks()5029 void ReorderCursorStrBlocks()
5030 {
5031 /* setup gstTextHighlightInfo */
5032 if (!UpdateTextHighlightInfo()) return;
5033
5034 curStrBlock = gstTextHighlightInfo.start_str_block_ptr;
5035 textCurIndex = gstTextHighlightInfo.start_index;
5036 endStrBlock = gstTextHighlightInfo.end_str_block_ptr;
5037 textEndIndex = gstTextHighlightInfo.end_index;
5038 }
5039
5040 /* --------------------- FindStringInMiniLines() --------------------- */
5041
5042 static
CaseDependentStrNCmp(buf1,buf2,str_len,case_sensitive)5043 int CaseDependentStrNCmp(buf1, buf2, str_len, case_sensitive)
5044 char *buf1, *buf2;
5045 int str_len, case_sensitive;
5046 {
5047 return (case_sensitive ? strncmp(buf1, buf2, str_len) :
5048 UtilStrNCaseCmp(buf1, buf2, str_len));
5049 }
5050
5051 static
MatchStringInOnlyThisStrBlock(pStrBlock,nIndex,str_to_match,str_len_to_match,case_sensitive,ppStartStrBlock,pn_start_index,ppEndStrBlock,pn_end_index)5052 int MatchStringInOnlyThisStrBlock(pStrBlock, nIndex, str_to_match,
5053 str_len_to_match, case_sensitive, ppStartStrBlock, pn_start_index,
5054 ppEndStrBlock, pn_end_index)
5055 StrBlockInfo *pStrBlock;
5056 int nIndex, str_len_to_match, case_sensitive;
5057 char *str_to_match;
5058 StrBlockInfo **ppStartStrBlock, **ppEndStrBlock;
5059 int *pn_start_index, *pn_end_index;
5060 /* return TRUE if found */
5061 {
5062 char *buf=(&pStrBlock->seg->dyn_str.s[nIndex]);
5063 int buf_len=pStrBlock->seg->dyn_str.sz-nIndex-1;
5064 int inc=(pStrBlock->seg->double_byte?2:1);
5065
5066 for ( ; buf_len >= str_len_to_match; buf+=inc, buf_len-=inc) {
5067 if (CaseDependentStrNCmp(buf, str_to_match, str_len_to_match,
5068 case_sensitive) == 0) {
5069 /* match! */
5070 *ppStartStrBlock = *ppEndStrBlock = pStrBlock;
5071 *pn_start_index = buf-pStrBlock->seg->dyn_str.s;
5072 *pn_end_index = (*pn_start_index)+str_len_to_match;
5073 return TRUE;
5074 }
5075 }
5076 return FALSE;
5077 }
5078
5079 static
MatchStringFromCursor(pStrBlock,nIndex,str_to_match,str_len_to_match,case_sensitive,ppStartStrBlock,pn_start_index,ppEndStrBlock,pn_end_index)5080 int MatchStringFromCursor(pStrBlock, nIndex, str_to_match, str_len_to_match,
5081 case_sensitive, ppStartStrBlock, pn_start_index, ppEndStrBlock,
5082 pn_end_index)
5083 StrBlockInfo *pStrBlock;
5084 int nIndex, str_len_to_match, case_sensitive;
5085 char *str_to_match;
5086 StrBlockInfo **ppStartStrBlock, **ppEndStrBlock;
5087 int *pn_start_index, *pn_end_index;
5088 /*
5089 * return TRUE if found
5090 *
5091 * If *ppStartStrBlock is NULL, this means that we are still trying to
5092 * find a prefix match.
5093 * If *ppStartStrBlock is non-NULL, that means the prefix is found, so
5094 * we must match starting at the beginning of every string.
5095 */
5096 {
5097 char *buf=NULL;
5098 int buf_len=0;
5099
5100 if (pStrBlock == NULL || pStrBlock->type != SB_SIMPLE) {
5101 return FALSE;
5102 }
5103 buf = (&pStrBlock->seg->dyn_str.s[nIndex]);
5104 buf_len = pStrBlock->seg->dyn_str.sz-nIndex-1;
5105
5106 if (*ppStartStrBlock == NULL) {
5107 /* still trying to find a prefix match */
5108 int inc=(pStrBlock->seg->double_byte?2:1);
5109
5110 if (buf_len >= str_len_to_match) {
5111 if (MatchStringInOnlyThisStrBlock(pStrBlock, nIndex, str_to_match,
5112 str_len_to_match, case_sensitive, ppStartStrBlock,
5113 pn_start_index, ppEndStrBlock, pn_end_index)) {
5114 return TRUE;
5115 }
5116 for ( ; buf_len >= str_len_to_match; buf+=inc, buf_len-=inc) {
5117 }
5118 }
5119 for ( ; buf_len > 0; buf+=inc, buf_len-=inc) {
5120 if (CaseDependentStrNCmp(buf, str_to_match, buf_len,
5121 case_sensitive) == 0) {
5122 /* got a prefix match */
5123 *ppStartStrBlock = pStrBlock;
5124 *pn_start_index = buf-pStrBlock->seg->dyn_str.s;
5125 if (MatchStringFromCursor(pStrBlock->next, 0,
5126 &str_to_match[buf_len], str_len_to_match-buf_len,
5127 case_sensitive, ppStartStrBlock, pn_start_index,
5128 ppEndStrBlock, pn_end_index)) {
5129 return TRUE;
5130 }
5131 *ppStartStrBlock = NULL;
5132 *pn_start_index = INVALID;
5133 }
5134 }
5135 } else {
5136 /* the leading chars of buf much match str_to_match */
5137 if (buf_len >= str_len_to_match) {
5138 if (CaseDependentStrNCmp(buf, str_to_match, str_len_to_match,
5139 case_sensitive) == 0) {
5140 /* match! */
5141 *ppEndStrBlock = pStrBlock;
5142 *pn_end_index = buf-pStrBlock->seg->dyn_str.s+str_len_to_match;
5143 return TRUE;
5144 }
5145 } else {
5146 if (CaseDependentStrNCmp(buf, str_to_match, buf_len,
5147 case_sensitive) == 0) {
5148 if (MatchStringFromCursor(pStrBlock->next, nIndex, str_to_match,
5149 str_len_to_match-buf_len, case_sensitive, ppStartStrBlock,
5150 pn_start_index, ppEndStrBlock, pn_end_index)) {
5151 return TRUE;
5152 }
5153 }
5154 }
5155 }
5156 return FALSE;
5157 }
5158
5159 static
FindStringInStrBlock(pStrBlock,pn_found_starting_point,str_to_match,str_len_to_match,case_sensitive,ppStartStrBlock,pn_start_index,ppEndStrBlock,pn_end_index)5160 int FindStringInStrBlock(pStrBlock, pn_found_starting_point, str_to_match,
5161 str_len_to_match, case_sensitive, ppStartStrBlock, pn_start_index,
5162 ppEndStrBlock, pn_end_index)
5163 StrBlockInfo *pStrBlock;
5164 int *pn_found_starting_point, str_len_to_match, case_sensitive;
5165 char *str_to_match;
5166 StrBlockInfo **ppStartStrBlock, **ppEndStrBlock;
5167 int *pn_start_index, *pn_end_index;
5168 /* return TRUE if found */
5169 {
5170 switch (pStrBlock->type) {
5171 case SB_SIMPLE:
5172 if (*pn_found_starting_point) {
5173 if (MatchStringFromCursor(pStrBlock, 0, str_to_match, str_len_to_match,
5174 case_sensitive, ppStartStrBlock, pn_start_index, ppEndStrBlock,
5175 pn_end_index)) {
5176 return TRUE;
5177 }
5178 } else if (pStrBlock == curStrBlock) {
5179 *pn_found_starting_point = TRUE;
5180 if (textCurIndex != pStrBlock->seg->dyn_str.sz-1 &&
5181 MatchStringFromCursor(pStrBlock,
5182 textCurIndex+(textHighlight?1:0), str_to_match, str_len_to_match,
5183 case_sensitive, ppStartStrBlock, pn_start_index, ppEndStrBlock,
5184 pn_end_index)) {
5185 return TRUE;
5186 }
5187 } else {
5188 /* still looking for curStrBlock */
5189 }
5190 break;
5191
5192 case SB_CHAR_SPACE: return FALSE;
5193
5194 case SB_SUPSUB_LEFT:
5195 case SB_SUPSUB_CENTER:
5196 case SB_SUPSUB_RIGHT:
5197 if (pStrBlock->sup != NULL) {
5198 if (FindStringInMiniLines(pStrBlock->sup, pn_found_starting_point,
5199 str_to_match, str_len_to_match, case_sensitive, ppStartStrBlock,
5200 pn_start_index, ppEndStrBlock, pn_end_index)) {
5201 return TRUE;
5202 }
5203 }
5204 if (pStrBlock->type == SB_SUPSUB_CENTER) {
5205 if (*pn_found_starting_point) {
5206 if (MatchStringInOnlyThisStrBlock(pStrBlock, 0, str_to_match,
5207 str_len_to_match, case_sensitive, ppStartStrBlock,
5208 pn_start_index, ppEndStrBlock, pn_end_index)) {
5209 return TRUE;
5210 }
5211 } else if (pStrBlock == curStrBlock) {
5212 *pn_found_starting_point = TRUE;
5213 if (textCurIndex != pStrBlock->seg->dyn_str.sz-1 &&
5214 MatchStringInOnlyThisStrBlock(pStrBlock,
5215 textCurIndex+(textHighlight?1:0), str_to_match,
5216 str_len_to_match, case_sensitive, ppStartStrBlock,
5217 pn_start_index, ppEndStrBlock, pn_end_index)) {
5218 return TRUE;
5219 }
5220 } else {
5221 /* still looking for curStrBlock */
5222 }
5223 }
5224 if (pStrBlock->sub != NULL) {
5225 if (FindStringInMiniLines(pStrBlock->sub, pn_found_starting_point,
5226 str_to_match, str_len_to_match, case_sensitive, ppStartStrBlock,
5227 pn_start_index, ppEndStrBlock, pn_end_index)) {
5228 return TRUE;
5229 }
5230 }
5231 break;
5232 }
5233 return FALSE;
5234 }
5235
5236 static
FindStringInMiniLine(pMiniLine,pn_found_starting_point,str_to_match,str_len_to_match,case_sensitive,ppStartStrBlock,pn_start_index,ppEndStrBlock,pn_end_index)5237 int FindStringInMiniLine(pMiniLine, pn_found_starting_point, str_to_match,
5238 str_len_to_match, case_sensitive, ppStartStrBlock, pn_start_index,
5239 ppEndStrBlock, pn_end_index)
5240 MiniLineInfo *pMiniLine;
5241 int *pn_found_starting_point, str_len_to_match, case_sensitive;
5242 char *str_to_match;
5243 StrBlockInfo **ppStartStrBlock, **ppEndStrBlock;
5244 int *pn_start_index, *pn_end_index;
5245 /* return TRUE if found */
5246 {
5247 StrBlockInfo *pStrBlock=NULL;
5248
5249 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
5250 pStrBlock=pStrBlock->next) {
5251 if (FindStringInStrBlock(pStrBlock, pn_found_starting_point,
5252 str_to_match, str_len_to_match, case_sensitive, ppStartStrBlock,
5253 pn_start_index, ppEndStrBlock, pn_end_index)) {
5254 return TRUE;
5255 }
5256 }
5257 return FALSE;
5258 }
5259
FindStringInMiniLines(minilines,pn_found_starting_point,str_to_match,str_len_to_match,case_sensitive,ppStartStrBlock,pn_start_index,ppEndStrBlock,pn_end_index)5260 int FindStringInMiniLines(minilines, pn_found_starting_point, str_to_match,
5261 str_len_to_match, case_sensitive, ppStartStrBlock, pn_start_index,
5262 ppEndStrBlock, pn_end_index)
5263 MiniLinesInfo *minilines;
5264 int *pn_found_starting_point, str_len_to_match, case_sensitive;
5265 char *str_to_match;
5266 StrBlockInfo **ppStartStrBlock, **ppEndStrBlock;
5267 int *pn_start_index, *pn_end_index;
5268 /* return TRUE if found */
5269 {
5270 MiniLineInfo *pMiniLine=NULL;
5271
5272 for (pMiniLine=minilines->first; pMiniLine != NULL;
5273 pMiniLine=pMiniLine->next) {
5274 if (FindStringInMiniLine(pMiniLine, pn_found_starting_point, str_to_match,
5275 str_len_to_match, case_sensitive, ppStartStrBlock, pn_start_index,
5276 ppEndStrBlock, pn_end_index)) {
5277 return TRUE;
5278 }
5279 }
5280 return FALSE;
5281 }
5282
5283 /* --------------------- CanBreakMiniLinesIntoWords() --------------------- */
5284
5285 static
CanBreakStrSegIntoWords(pStrSeg)5286 int CanBreakStrSegIntoWords(pStrSeg)
5287 StrSegInfo *pStrSeg;
5288 {
5289 return (strchr(pStrSeg->dyn_str.s, ' ') != NULL);
5290 }
5291
5292 static
CanBreakStrBlockIntoWords(pStrBlock)5293 int CanBreakStrBlockIntoWords(pStrBlock)
5294 StrBlockInfo *pStrBlock;
5295 {
5296 switch (pStrBlock->type) {
5297 case SB_SIMPLE: return CanBreakStrSegIntoWords(pStrBlock->seg);
5298
5299 case SB_CHAR_SPACE: return TRUE;
5300
5301 case SB_SUPSUB_LEFT:
5302 case SB_SUPSUB_CENTER:
5303 case SB_SUPSUB_RIGHT:
5304 if (pStrBlock->sup != NULL) {
5305 if (!BlankMiniLines(pStrBlock->sup)) {
5306 return TRUE;
5307 }
5308 }
5309 if (pStrBlock->sub != NULL) {
5310 if (!BlankMiniLines(pStrBlock->sub)) {
5311 return TRUE;
5312 }
5313 }
5314 if (pStrBlock->type == SB_SUPSUB_CENTER) {
5315 /* pStrBlock->seg better not be NULL or it will crash */
5316 if (CanBreakStrSegIntoWords(pStrBlock->seg)) {
5317 return TRUE;
5318 }
5319 }
5320 break;
5321 }
5322 return FALSE;
5323 }
5324
5325 static
CanBreakMiniLineIntoWords(pMiniLine)5326 int CanBreakMiniLineIntoWords(pMiniLine)
5327 MiniLineInfo *pMiniLine;
5328 {
5329 StrBlockInfo *pStrBlock=NULL;
5330
5331 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
5332 pStrBlock=pStrBlock->next) {
5333 if (pStrBlock->next != NULL) {
5334 return TRUE;
5335 }
5336 if (CanBreakStrBlockIntoWords(pStrBlock)) {
5337 return TRUE;
5338 }
5339 }
5340 return FALSE;
5341 }
5342
CanBreakMiniLinesIntoWords(minilines)5343 int CanBreakMiniLinesIntoWords(minilines)
5344 MiniLinesInfo *minilines;
5345 {
5346 MiniLineInfo *pMiniLine=NULL;
5347
5348 for (pMiniLine=minilines->first; pMiniLine != NULL;
5349 pMiniLine=pMiniLine->next) {
5350 if (pMiniLine->next != NULL) {
5351 return TRUE;
5352 }
5353 if (CanBreakMiniLineIntoWords(pMiniLine)) {
5354 return TRUE;
5355 }
5356 }
5357 return FALSE;
5358 }
5359
5360 /* --------------------- BreakMiniLines() --------------------- */
5361
5362 static
FinalizeBreakStrSeg(new_obj,x,baseline_y,prototype,tx_to_move,ty_to_move,poli)5363 void FinalizeBreakStrSeg(new_obj, x, baseline_y, prototype, tx_to_move,
5364 ty_to_move, poli)
5365 struct ObjRec *new_obj;
5366 int x, baseline_y;
5367 struct ObjRec *prototype;
5368 int tx_to_move, ty_to_move;
5369 ObjListInfo *poli;
5370 {
5371 struct SelRec *new_sel_ptr=NULL;
5372 struct TextRec *text_ptr=new_obj->detail.t;
5373 MiniLinesInfo *minilines=(&text_ptr->minilines);
5374 int x_pos=x, y_pos=0, w=0, dx=0, dy=0;
5375
5376 minilines->first->v_gap = 0;
5377
5378 new_obj->x = x;
5379 text_ptr->baseline_y = baseline_y;
5380 UpdTextBBox(new_obj);
5381 y_pos = new_obj->y;
5382
5383 dx = dy = 0;
5384 w = minilines->w;
5385
5386 switch (minilines->just) {
5387 case JUST_L: break;
5388 case JUST_C: dx = (w>>1); break;
5389 case JUST_R: dx = w; break;
5390 }
5391 if (new_obj->ctm != NULL) {
5392 int new_x=0, new_y=0;
5393
5394 TransformPointThroughCTM(x_pos+dx-prototype->x,
5395 y_pos+dy-prototype->y, prototype->ctm, &new_x, &new_y);
5396 new_x += prototype->x;
5397 new_y += prototype->y;
5398 free(new_obj->ctm);
5399 new_obj->ctm = NULL;
5400 UpdTextBBox(new_obj);
5401 SetCTM(new_obj, prototype->ctm);
5402 MoveObj(new_obj, new_x-new_obj->x-tx_to_move,
5403 new_y-new_obj->y-ty_to_move);
5404 } else {
5405 MoveObj(new_obj, dx, dy);
5406 }
5407 new_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
5408 if (new_sel_ptr == NULL) FailAllocMessage();
5409 new_sel_ptr->obj = new_obj;
5410
5411 new_sel_ptr->next = poli->top_sel;
5412 new_obj->next = poli->top_obj;
5413 if (poli->top_sel == NULL) {
5414 poli->bot_sel = new_sel_ptr;
5415 poli->bot_obj = new_obj;
5416 } else {
5417 poli->top_sel->prev = new_sel_ptr;
5418 poli->top_obj->prev = new_obj;
5419 }
5420 poli->top_sel = new_sel_ptr;
5421 poli->top_obj = new_obj;
5422 poli->top_sel->prev = NULL;
5423 poli->top_obj->prev = NULL;
5424 poli->count++;
5425 }
5426
5427 static
BreakStrSeg(pSrcStrSeg,into_words,x,baseline_y,prototype,tx_to_move,ty_to_move,poli)5428 void BreakStrSeg(pSrcStrSeg, into_words, x, baseline_y, prototype, tx_to_move,
5429 ty_to_move, poli)
5430 StrSegInfo *pSrcStrSeg;
5431 int into_words, x, baseline_y;
5432 struct ObjRec *prototype;
5433 int tx_to_move, ty_to_move;
5434 ObjListInfo *poli;
5435 /*
5436 * x is the left edge of the string segment.
5437 */
5438 {
5439 char *c_ptr=pSrcStrSeg->dyn_str.s;
5440 int is_gap=(*c_ptr == ' ' || *c_ptr == '\t');
5441
5442 if (!TrySetCanvasFont(pSrcStrSeg->font, pSrcStrSeg->style,
5443 SzUnitToFontSize(pSrcStrSeg->sz_unit), TRUE, NULL)) {
5444 return;
5445 }
5446 while (*c_ptr != '\0') {
5447 struct ObjRec *new_obj=DupObj(prototype);
5448 StrSegInfo *pDestStrSeg=NULL;
5449 char *word_start=NULL, saved_ch='\0';
5450 int w=0, all_blanks=FALSE;
5451
5452 FreeStrSeg(GetTextObjFirstStrSeg(new_obj));
5453 DupStrSeg(new_obj->detail.t->minilines.first->first_block,
5454 pSrcStrSeg);
5455 pDestStrSeg = GetTextObjFirstStrSeg(new_obj);
5456 if (into_words) {
5457 char *prev_ptr=NULL;
5458
5459 word_start = c_ptr;
5460 if (is_gap) {
5461 for ( ; *c_ptr == ' ' || *c_ptr == '\t'; c_ptr++) {
5462 prev_ptr = c_ptr;
5463 }
5464 /* all_blanks = TRUE; */
5465 } else {
5466 for ( ; *c_ptr != ' ' && *c_ptr != '\t' && *c_ptr != '\0';
5467 c_ptr++) {
5468 prev_ptr = c_ptr;
5469 }
5470 }
5471 saved_ch = *c_ptr;
5472 *c_ptr = '\0';
5473 DynStrSet(&pDestStrSeg->dyn_str, word_start);
5474 w = MyTextWidth(canvasFontPtr, pDestStrSeg->dyn_str.s,
5475 pDestStrSeg->dyn_str.sz-1);
5476 *c_ptr = saved_ch;
5477 if (prev_ptr != NULL) c_ptr = prev_ptr;
5478
5479 is_gap = !is_gap;
5480 } else {
5481 if (pSrcStrSeg->double_byte) {
5482 strncpy(pDestStrSeg->dyn_str.s, c_ptr, 2);
5483 pDestStrSeg->dyn_str.s[2] = '\0';
5484 pDestStrSeg->dyn_str.sz = 3;
5485 w = MyTextWidth(canvasFontPtr, pDestStrSeg->dyn_str.s, 2);
5486 } else {
5487 *pDestStrSeg->dyn_str.s = *c_ptr;
5488 pDestStrSeg->dyn_str.s[1] = '\0';
5489 pDestStrSeg->dyn_str.sz = 2;
5490 w = MyTextWidth(canvasFontPtr, pDestStrSeg->dyn_str.s, 1);
5491 }
5492 }
5493 if (c_ptr == NULL) {
5494 FreeObj(new_obj);
5495 break;
5496 } else if (all_blanks) {
5497 FreeObj(new_obj);
5498 } else {
5499 FinalizeBreakStrSeg(new_obj, x, baseline_y, prototype, tx_to_move,
5500 ty_to_move, poli);
5501 }
5502 x += w;
5503 if (*c_ptr == '\0') break;
5504
5505 if (pSrcStrSeg->double_byte) {
5506 c_ptr += 2;
5507 } else {
5508 c_ptr++;
5509 }
5510 }
5511 }
5512
5513 static
BreakStrBlock(pStrBlock,into_words,x,baseline_y,prototype,tx_to_move,ty_to_move,poli)5514 void BreakStrBlock(pStrBlock, into_words, x, baseline_y, prototype, tx_to_move,
5515 ty_to_move, poli)
5516 StrBlockInfo *pStrBlock;
5517 int into_words, x, baseline_y;
5518 struct ObjRec *prototype;
5519 int tx_to_move, ty_to_move;
5520 ObjListInfo *poli;
5521 /*
5522 * x is the left edge of the string block.
5523 */
5524 {
5525 int saved_baseline_y=baseline_y;
5526 int block_w=pStrBlock->w;
5527
5528 switch (pStrBlock->type) {
5529 case SB_SIMPLE:
5530 BreakStrSeg(pStrBlock->seg, into_words, x, baseline_y, prototype,
5531 tx_to_move, ty_to_move, poli);
5532 break;
5533
5534 case SB_CHAR_SPACE: break;
5535
5536 case SB_SUPSUB_LEFT:
5537 case SB_SUPSUB_CENTER:
5538 case SB_SUPSUB_RIGHT:
5539 switch (pStrBlock->type) {
5540 case SB_SUPSUB_LEFT: x += block_w; break;
5541 case SB_SUPSUB_CENTER: x += (block_w>>1); break;
5542 case SB_SUPSUB_RIGHT: break;
5543 }
5544 if (pStrBlock->type == SB_SUPSUB_CENTER) {
5545 /* pStrBlock->seg better not be NULL or it will crash */
5546 baseline_y = saved_baseline_y;
5547 BreakStrSeg(pStrBlock->seg, into_words, x-((pStrBlock->seg->w)>>1),
5548 baseline_y, prototype, tx_to_move, ty_to_move, poli);
5549 }
5550 if (pStrBlock->sup != NULL) {
5551 baseline_y = saved_baseline_y+pStrBlock->sup->baseline_offset;
5552 if (pStrBlock->type == SB_SUPSUB_CENTER) {
5553 baseline_y -= pStrBlock->seg->asc;
5554 }
5555 BreakMiniLines(pStrBlock->sup, into_words, x, baseline_y, prototype,
5556 tx_to_move, ty_to_move, poli);
5557 }
5558 if (pStrBlock->sub != NULL) {
5559 baseline_y = saved_baseline_y+pStrBlock->sub->baseline_offset;
5560 if (pStrBlock->type == SB_SUPSUB_CENTER) {
5561 baseline_y += pStrBlock->seg->des;
5562 }
5563 BreakMiniLines(pStrBlock->sub, into_words, x, baseline_y, prototype,
5564 tx_to_move, ty_to_move, poli);
5565 }
5566 break;
5567 }
5568 }
5569
5570 static
BreakMiniLine(pMiniLine,into_words,x,baseline_y,prototype,tx_to_move,ty_to_move,poli)5571 void BreakMiniLine(pMiniLine, into_words, x, baseline_y, prototype, tx_to_move,
5572 ty_to_move, poli)
5573 MiniLineInfo *pMiniLine;
5574 int into_words, x, baseline_y;
5575 struct ObjRec *prototype;
5576 int tx_to_move, ty_to_move;
5577 ObjListInfo *poli;
5578 /*
5579 * x is the left edge of the miniline and baseline_y has been adjusted by
5580 * pMiniLine->v_gap.
5581 */
5582 {
5583 StrBlockInfo *pStrBlock=NULL;
5584
5585 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
5586 pStrBlock=pStrBlock->next) {
5587 BreakStrBlock(pStrBlock, into_words, x, baseline_y, prototype, tx_to_move,
5588 ty_to_move, poli);
5589
5590 x += pStrBlock->w;
5591 }
5592 }
5593
BreakMiniLines(minilines,how,x,baseline_y,prototype,tx_to_move,ty_to_move,poli)5594 void BreakMiniLines(minilines, how, x, baseline_y, prototype, tx_to_move,
5595 ty_to_move, poli)
5596 MiniLinesInfo *minilines;
5597 int how, x, baseline_y;
5598 struct ObjRec *prototype;
5599 int tx_to_move, ty_to_move;
5600 ObjListInfo *poli;
5601 /*
5602 * x is the origin of the minilines (not the left edge)
5603 */
5604 {
5605 MiniLineInfo *pMiniLine=NULL, *pNextMiniLine=NULL;
5606 int v_space=minilines->v_space;
5607 int saved_x=x;
5608
5609 for (pMiniLine=minilines->first; pMiniLine != NULL;
5610 pMiniLine=pNextMiniLine) {
5611 pNextMiniLine = pMiniLine->next;
5612 baseline_y += pMiniLine->v_gap;
5613
5614 switch (minilines->just) {
5615 case JUST_L: x = saved_x; break;
5616 case JUST_C: x = saved_x - ((pMiniLine->w)>>1); break;
5617 case JUST_R: x = saved_x - pMiniLine->w; break;
5618 }
5619 if (how == BREAK_LINE) {
5620 struct ObjRec *new_obj=DupObj(prototype);
5621 MiniLinesInfo *new_minilines=(&new_obj->detail.t->minilines);
5622
5623 FreeMiniLines(new_minilines, FALSE);
5624 DupMiniLine(pMiniLine, new_minilines, NULL, &new_minilines->first,
5625 &new_minilines->last);
5626 FinalizeBreakStrSeg(new_obj, x, baseline_y, prototype, tx_to_move,
5627 ty_to_move, poli);
5628 } else {
5629 BreakMiniLine(pMiniLine, (how==BREAK_WORD), x, baseline_y, prototype,
5630 tx_to_move, ty_to_move, poli);
5631 }
5632 baseline_y += pMiniLine->des + v_space;
5633 if (pMiniLine->next != NULL) {
5634 baseline_y += pMiniLine->next->asc;
5635 }
5636 }
5637 }
5638
5639 /* --------------------- DumpMiniLines() --------------------- */
5640
5641 static
DumpGSave(FP,do_dump,indent)5642 void DumpGSave(FP, do_dump, indent)
5643 FILE *FP;
5644 int do_dump, indent;
5645 {
5646 if (do_dump) {
5647 DumpIndentString(FP, indent);
5648 fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
5649 }
5650 }
5651
5652 static
DumpGRestore(FP,do_dump,indent)5653 void DumpGRestore(FP, do_dump, indent)
5654 FILE *FP;
5655 int do_dump, indent;
5656 {
5657 if (do_dump) {
5658 DumpIndentString(FP, indent);
5659 fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
5660 }
5661 }
5662
5663 static
DumpSetFont(FP,font,font_name,double_byte,style,sz_unit,pn_cancel_double_byte_mod_bytes)5664 void DumpSetFont(FP, font, font_name, double_byte, style, sz_unit,
5665 pn_cancel_double_byte_mod_bytes)
5666 FILE *FP;
5667 int font, double_byte, style, sz_unit, *pn_cancel_double_byte_mod_bytes;
5668 char *font_name;
5669 /*
5670 * The only known condition for setting *cancel_double_byte_mod_bytes to
5671 * TRUE is when Japanese EUC fonts are used.
5672 */
5673 {
5674 char buf[MAXSTRING], font_str[MAXSTRING], real_font_str[MAXSTRING];
5675 char *ps_findfont_cmd=gPsCmd[PS_FINDFONT];
5676 float fSize=(float)0;
5677
5678 if (double_byte) {
5679 #ifdef _PS_USE_EUC_FONT
5680 int euc_font=FALSE;
5681 char combined_font_str[MAXSTRING];
5682 #endif /* _PS_USE_EUC_FONT */
5683
5684 if (PRTGIF && font_name != NULL) {
5685 sprintf(font_str, "/%s", font_name);
5686 } else {
5687 GetPSFontStr(font, style, font_str);
5688 }
5689 strcpy(real_font_str, font_str);
5690 MapAliasedPSFontName(real_font_str, sizeof(real_font_str));
5691
5692 if (pn_cancel_double_byte_mod_bytes != NULL &&
5693 strstr(real_font_str, "-EUC-") != NULL) {
5694 *pn_cancel_double_byte_mod_bytes = TRUE;
5695 }
5696 #ifdef _PS_USE_EUC_FONT
5697 /* do not translate -- program constants */
5698 euc_font = (strstr(font_str, "-EUC-") != NULL);
5699 if (euc_font) {
5700 if (preDumpSetup) PSUseEucFont();
5701 sprintf(combined_font_str, "/Courier-%s", &font_str[1]);
5702 fprintf(FP, "%s /Courier %s eucfont\n", combined_font_str, font_str);
5703 fprintf(FP, "%s ", combined_font_str);
5704 UpdateDocumentFonts(&font_str[1]);
5705 UpdateDocumentFonts("Courier");
5706 } else {
5707 fprintf(FP, "%s ", font_str);
5708 UpdateDocumentFonts(&font_str[1]);
5709 }
5710 #else /* ~_PS_USE_EUC_FONT */
5711 fprintf(FP, "%s ", font_str);
5712 UpdateDocumentFonts(&real_font_str[1]);
5713 #endif /* _PS_USE_EUC_FONT */
5714 } else {
5715 if (PRTGIF && font_name != NULL) {
5716 sprintf(font_str, "/%s", font_name);
5717 } else {
5718 GetPSFontStr(font, style, font_str);
5719 }
5720 strcpy(real_font_str, font_str);
5721 MapAliasedPSFontName(real_font_str, sizeof(real_font_str));
5722
5723 if (NeedEncode(&font_str[1], font, style)) {
5724 #ifdef _PRTGIF_USE_ISO_LATIN_1_ALWAYS
5725 if (PRTGIF && !cmdLineOpenDisplay) {
5726 if (preDumpSetup) PSUseReencode(NULL);
5727 fprintf(FP, "%s %s-8 latin1.vec ", real_font_str, font_str);
5728 ps_findfont_cmd = "TGFF8";
5729 } else {
5730 fprintf(FP, "%s-8 ", font_str);
5731 }
5732 #else /* ~_PRTGIF_USE_ISO_LATIN_1_ALWAYS */
5733 fprintf(FP, "%s-8 ", font_str);
5734 #endif /* _PRTGIF_USE_ISO_LATIN_1_ALWAYS */
5735 } else {
5736 fprintf(FP, "%s ", real_font_str);
5737 }
5738 UpdateDocumentFonts(&real_font_str[1]);
5739 }
5740 fSize = (float)(((float)sz_unit)/((float)NUM_SZ_UNIT_PER_FONT_SIZE));
5741 FormatFloat(&fSize, buf);
5742
5743 fprintf(FP, "%s ", ps_findfont_cmd);
5744 #ifndef _PS_USE_EUC_FONT
5745 if (double_byte) {
5746 fprintf(FP, "dup /WMode known {dup /WMode get 1 eq ");
5747 #ifdef _VERT_FONT_OFFSET_POINT_4
5748 fprintf(FP, "{[0 1 -1 0 0 0.4] makefont} if} if\n");
5749 #else /* ~_VERT_FONT_OFFSET_POINT_4 */
5750 fprintf(FP, "{[0 1 -1 0 0 0.3] makefont} if} if\n");
5751 #endif /* _VERT_FONT_OFFSET_POINT_4 */
5752 }
5753 #endif /* ~_PS_USE_EUC_FONT */
5754 fprintf(FP, "[%s 0 0 -%s 0 0] %s\n", buf, buf, gPsCmd[PS_MAKESETFONT]);
5755 }
5756
5757 static
DumpStrSeg(pStrSeg,just,x,baseline_y,FP,pBBox,do_dump,indent)5758 void DumpStrSeg(pStrSeg, just, x, baseline_y, FP, pBBox, do_dump, indent)
5759 StrSegInfo *pStrSeg;
5760 int just, x, baseline_y, do_dump, indent;
5761 FILE *FP;
5762 struct BBRec *pBBox;
5763 {
5764 int font=pStrSeg->font, style=pStrSeg->style, sz_unit=pStrSeg->sz_unit;
5765 int double_byte=pStrSeg->double_byte, color_index=pStrSeg->color;
5766 int double_byte_mod_bytes=pStrSeg->double_byte_mod_bytes;
5767 int cancel_double_byte_mod_bytes=FALSE;
5768 int asc=(pStrSeg->read_only ? pStrSeg->orig_asc : pStrSeg->asc);
5769 char *font_name=pStrSeg->font_name;
5770
5771 if (*pStrSeg->dyn_str.s == '\0') {
5772 if (!do_dump) {
5773 DumpIndentString(FP, indent);
5774 fprintf(FP, "0\n");
5775 }
5776 return;
5777 }
5778 if (do_dump) {
5779 DumpIndentString(FP, indent);
5780 if (penPat == BACKPAT) {
5781 fprintf(FP, "1 %s\n", gPsCmd[PS_SETGRAY]);
5782 } else if (colorDump || !useGray) {
5783 DumpRGBColorLine(FP, color_index, 0, TRUE);
5784 } else if (penPat == SOLIDPAT) {
5785 fprintf(FP, "0 %s\n", gPsCmd[PS_SETGRAY]);
5786 } else {
5787 GrayCheck(penPat);
5788 fprintf(FP, "%s %s\n", GrayStr(penPat), gPsCmd[PS_SETGRAY]);
5789 }
5790 }
5791 DumpIndentString(FP, indent);
5792 DumpSetFont(FP, font, font_name, double_byte, style, sz_unit,
5793 &cancel_double_byte_mod_bytes);
5794 DumpIndentString(FP, indent);
5795 fprintf(FP, "(");
5796 DumpOneStr(FP, font, double_byte,
5797 double_byte_mod_bytes && !cancel_double_byte_mod_bytes,
5798 pStrSeg->dyn_str.s);
5799 if (do_dump) {
5800 int underline_on=pStrSeg->underline_on;
5801 int overline_on=pStrSeg->overline_on;
5802
5803 if (just == JUST_C && preDumpSetup) PSUseCenterText();
5804
5805 if ((colorDump || !useGray) && penPat > BACKPAT) {
5806 if (just == JUST_C) {
5807 fprintf(FP, ") TGCTX %s TGSW %s %s true %s %s %s\n",
5808 gPsCmd[PS_DUP], gPsCmd[PS_EXCH], gPsCmd[PS_GSAVE],
5809 gPsCmd[PS_CHARPATH], gPsCmd[PS_CLIP], gPsCmd[PS_NEWPATH]);
5810 } else {
5811 fprintf(FP, ") %s TGSW %s %s true %s %s %s\n",
5812 gPsCmd[PS_DUP], gPsCmd[PS_EXCH], gPsCmd[PS_GSAVE],
5813 gPsCmd[PS_CHARPATH], gPsCmd[PS_CLIP], gPsCmd[PS_NEWPATH]);
5814 }
5815 if (preDumpSetup) PSUseColorPattern();
5816 DumpPatFill(FP, penPat, *pBBox, indent, FALSE);
5817 if (underline_on && overline_on) {
5818 fprintf(FP, " %s %s %s 0 %s\n", gPsCmd[PS_GRESTORE], gPsCmd[PS_DUP],
5819 gPsCmd[PS_DUP], gPsCmd[PS_RMOVETO]);
5820 } else if (underline_on || overline_on) {
5821 fprintf(FP, " %s %s 0 %s\n", gPsCmd[PS_GRESTORE], gPsCmd[PS_DUP],
5822 gPsCmd[PS_RMOVETO]);
5823 } else {
5824 fprintf(FP, " %s 0 %s\n", gPsCmd[PS_GRESTORE], gPsCmd[PS_RMOVETO]);
5825 }
5826 } else {
5827 if (just == JUST_C) {
5828 if (underline_on && overline_on) {
5829 fprintf(FP, ") %s %s TGSW %s TGCTX %s\n", gPsCmd[PS_DUP],
5830 gPsCmd[PS_DUP], gPsCmd[PS_EXCH], gPsCmd[PS_SHOW]);
5831 } else if (underline_on || overline_on) {
5832 fprintf(FP, ") %s TGSW %s TGCTX %s\n",
5833 gPsCmd[PS_DUP], gPsCmd[PS_EXCH], gPsCmd[PS_SHOW]);
5834 } else {
5835 fprintf(FP, ") TGCTX %s\n", gPsCmd[PS_SHOW]);
5836 }
5837 } else {
5838 if (underline_on && overline_on) {
5839 fprintf(FP, ") %s %s TGSW %s %s\n", gPsCmd[PS_DUP],
5840 gPsCmd[PS_DUP], gPsCmd[PS_EXCH], gPsCmd[PS_SHOW]);
5841 } else if (underline_on || overline_on) {
5842 fprintf(FP, ") %s TGSW %s %s\n",
5843 gPsCmd[PS_DUP], gPsCmd[PS_EXCH], gPsCmd[PS_SHOW]);
5844 } else {
5845 fprintf(FP, ") %s\n", gPsCmd[PS_SHOW]);
5846 }
5847 }
5848 }
5849 if (underline_on) {
5850 DumpIndentString(FP, indent);
5851 fprintf(FP, "%s %s %s 0 %1d %s %s 0 %s %s %s\n",
5852 gPsCmd[PS_GSAVE], gPsCmd[PS_CURRENTPOINT],
5853 gPsCmd[PS_MOVETO], curUnderlineYOffset, gPsCmd[PS_RMOVETO],
5854 gPsCmd[PS_NEG], gPsCmd[PS_RLINETO], gPsCmd[PS_STROKE],
5855 gPsCmd[PS_GRESTORE]);
5856 }
5857 if (overline_on) {
5858 DumpIndentString(FP, indent);
5859 fprintf(FP, "%s %s %s 0 %1d %s %s 0 %1d %s %s %s 0 %s %s %s\n",
5860 gPsCmd[PS_GSAVE], gPsCmd[PS_CURRENTPOINT], gPsCmd[PS_MOVETO],
5861 curOverlineYOffset, gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO],
5862 asc, gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO],
5863 gPsCmd[PS_NEG], gPsCmd[PS_RLINETO], gPsCmd[PS_STROKE],
5864 gPsCmd[PS_GRESTORE]);
5865 }
5866 } else {
5867 fprintf(FP, ") TGSW \n");
5868 }
5869 }
5870
5871 static
DumpSupSubBlock(pStrBlock,x,baseline_y,FP,pBBox,do_dump,indent)5872 void DumpSupSubBlock(pStrBlock, x, baseline_y, FP, pBBox, do_dump, indent)
5873 StrBlockInfo *pStrBlock;
5874 int x, baseline_y, do_dump, indent;
5875 FILE *FP;
5876 struct BBRec *pBBox;
5877 {
5878 int saved_baseline_y=baseline_y;
5879
5880 if (!do_dump) {
5881 DumpIndentString(FP, indent);
5882 fprintf(FP, "0\n");
5883 }
5884 if (pStrBlock->type == SB_SUPSUB_CENTER) {
5885 /* pStrBlock->seg better not be NULL or it will crash */
5886 DumpGSave(FP, do_dump, indent);
5887
5888 baseline_y = saved_baseline_y;
5889 DumpStrSeg(pStrBlock->seg, JUST_C, x-((pStrBlock->seg->w)>>1), baseline_y,
5890 FP, pBBox, do_dump, indent+2);
5891 if (!do_dump) {
5892 DumpIndentString(FP, indent);
5893 fprintf(FP, "TGMAX\n");
5894 }
5895 DumpGRestore(FP, do_dump, indent);
5896 }
5897 if (pStrBlock->sup != NULL) {
5898 if (!BlankMiniLines(pStrBlock->sup)) {
5899 DumpGSave(FP, do_dump, indent);
5900 baseline_y = saved_baseline_y+pStrBlock->sup->baseline_offset;
5901 if (do_dump && pStrBlock->sup->baseline_offset != 0) {
5902 DumpIndentString(FP, indent+2);
5903 fprintf(FP, "0 %1d %s\n", pStrBlock->sup->baseline_offset,
5904 gPsCmd[PS_RMOVETO]);
5905 }
5906 if (pStrBlock->type == SB_SUPSUB_CENTER && do_dump &&
5907 pStrBlock->seg->asc != 0) {
5908 /*
5909 * shift the superscript up more because SB_SUPSUB_CENTER
5910 */
5911 baseline_y -= pStrBlock->seg->asc;
5912 DumpIndentString(FP, indent);
5913 fprintf(FP, "0 %1d %s %s\n", pStrBlock->seg->asc, gPsCmd[PS_NEG],
5914 gPsCmd[PS_RMOVETO]);
5915 }
5916 DumpMiniLines(pStrBlock->sup, x, baseline_y, FP, pBBox, do_dump,
5917 indent+2);
5918 if (!do_dump) {
5919 DumpIndentString(FP, indent);
5920 fprintf(FP, "TGMAX\n");
5921 }
5922 DumpGRestore(FP, do_dump, indent);
5923 }
5924 }
5925 if (pStrBlock->sub != NULL) {
5926 if (!BlankMiniLines(pStrBlock->sub)) {
5927 DumpGSave(FP, do_dump, indent);
5928 baseline_y = saved_baseline_y+pStrBlock->sub->baseline_offset;
5929 if (do_dump && pStrBlock->sub->baseline_offset != 0) {
5930 DumpIndentString(FP, indent+2);
5931 fprintf(FP, "0 %1d %s\n", pStrBlock->sub->baseline_offset,
5932 gPsCmd[PS_RMOVETO]);
5933 }
5934 if (pStrBlock->type == SB_SUPSUB_CENTER && do_dump &&
5935 pStrBlock->seg->des != 0) {
5936 /*
5937 * shift the subscript down more because SB_SUPSUB_CENTER
5938 */
5939 baseline_y += pStrBlock->seg->des;
5940 DumpIndentString(FP, indent);
5941 fprintf(FP, "0 %1d %s\n", pStrBlock->seg->des, gPsCmd[PS_RMOVETO]);
5942 }
5943 DumpMiniLines(pStrBlock->sub, x, baseline_y, FP, pBBox, do_dump,
5944 indent+2);
5945 if (!do_dump) {
5946 DumpIndentString(FP, indent);
5947 fprintf(FP, "TGMAX\n");
5948 }
5949 DumpGRestore(FP, do_dump, indent);
5950 }
5951 }
5952 }
5953
5954 static
DumpStrBlock(pStrBlock,x,baseline_y,FP,pBBox,do_dump,indent)5955 void DumpStrBlock(pStrBlock, x, baseline_y, FP, pBBox, do_dump, indent)
5956 StrBlockInfo *pStrBlock;
5957 int x, baseline_y, do_dump, indent;
5958 FILE *FP;
5959 struct BBRec *pBBox;
5960 /*
5961 * x is the left edge of the string block.
5962 */
5963 {
5964 int block_w=pStrBlock->w;
5965
5966 switch (pStrBlock->type) {
5967 case SB_SIMPLE:
5968 DumpStrSeg(pStrBlock->seg, JUST_L, x, baseline_y, FP, pBBox, do_dump,
5969 indent+2);
5970 break;
5971
5972 case SB_CHAR_SPACE:
5973 if (do_dump) {
5974 fprintf(FP, "%1d 0 %s\n", pStrBlock->special_char_w,
5975 gPsCmd[PS_RMOVETO]);
5976 } else {
5977 fprintf(FP, "%1d \n", pStrBlock->special_char_w);
5978 }
5979 break;
5980
5981 case SB_SUPSUB_LEFT:
5982 case SB_SUPSUB_CENTER:
5983 case SB_SUPSUB_RIGHT:
5984 if (!do_dump) {
5985 DumpIndentString(FP, indent);
5986 fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
5987 DumpIndentString(FP, indent);
5988 fprintf(FP, "0\n");
5989 }
5990 if (do_dump) {
5991 switch (pStrBlock->type) {
5992 case SB_SUPSUB_LEFT:
5993 case SB_SUPSUB_CENTER:
5994 if (do_dump) {
5995 DumpGSave(FP, do_dump, indent);
5996 DumpIndentString(FP, indent);
5997 fprintf(FP, "0\n");
5998 }
5999 if (pStrBlock->type == SB_SUPSUB_CENTER) {
6000 x += (block_w>>1);
6001 } else {
6002 x += block_w;
6003 }
6004 DumpSupSubBlock(pStrBlock, x, baseline_y, FP, pBBox, FALSE,
6005 indent+2);
6006 DumpIndentString(FP, indent);
6007 fprintf(FP, "TGMAX\n");
6008 DumpGRestore(FP, do_dump, indent);
6009 DumpGSave(FP, do_dump, indent);
6010 DumpIndentString(FP, indent);
6011 fprintf(FP, "%s\n", gPsCmd[PS_DUP]);
6012
6013 DumpIndentString(FP, indent);
6014 if (pStrBlock->type == SB_SUPSUB_CENTER) {
6015 fprintf(FP, "2 %s 0 %s\n", gPsCmd[PS_DIV], gPsCmd[PS_RMOVETO]);
6016 } else {
6017 fprintf(FP, "0 %s\n", gPsCmd[PS_RMOVETO]);
6018 }
6019 /* now dump it */
6020 DumpSupSubBlock(pStrBlock, x, baseline_y, FP, pBBox, TRUE,
6021 indent+2);
6022
6023 DumpGRestore(FP, do_dump, indent);
6024 DumpIndentString(FP, indent);
6025 fprintf(FP, "0 %s\n", gPsCmd[PS_RMOVETO]);
6026 break;
6027 case SB_SUPSUB_RIGHT:
6028 DumpGSave(FP, do_dump, indent);
6029 DumpSupSubBlock(pStrBlock, x, baseline_y, FP, pBBox, TRUE,
6030 indent+2);
6031 DumpGRestore(FP, do_dump, indent);
6032 DumpSupSubBlock(pStrBlock, x, baseline_y, FP, pBBox, FALSE,
6033 indent+2);
6034 DumpIndentString(FP, indent);
6035 fprintf(FP, "0 %s\n", gPsCmd[PS_RMOVETO]);
6036 break;
6037 }
6038 } else {
6039 DumpSupSubBlock(pStrBlock, x, baseline_y, FP, pBBox, FALSE, indent+2);
6040 DumpIndentString(FP, indent);
6041 fprintf(FP, "TGMAX\n");
6042 }
6043 if (!do_dump) {
6044 DumpIndentString(FP, indent);
6045 fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
6046 }
6047 break;
6048 }
6049 }
6050
6051 static
DumpMiniLine(pMiniLine,x,baseline_y,FP,pBBox,do_dump,indent)6052 void DumpMiniLine(pMiniLine, x, baseline_y, FP, pBBox, do_dump, indent)
6053 MiniLineInfo *pMiniLine;
6054 int x, baseline_y, do_dump, indent;
6055 FILE *FP;
6056 struct BBRec *pBBox;
6057 /*
6058 * x is the left edge of the miniline and baseline_y has been adjusted by
6059 * pMiniLine->v_gap.
6060 */
6061 {
6062 StrBlockInfo *pStrBlock=NULL;
6063
6064 if (!do_dump) {
6065 /*
6066 * compute the sum of the widths and leave it on the stop of stack
6067 */
6068 DumpIndentString(FP, indent);
6069 fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
6070 DumpIndentString(FP, indent);
6071 fprintf(FP, "0\n");
6072 }
6073 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
6074 pStrBlock=pStrBlock->next) {
6075 DumpStrBlock(pStrBlock, x, baseline_y, FP, pBBox, do_dump, indent+2);
6076 if (!do_dump) {
6077 DumpIndentString(FP, indent);
6078 fprintf(FP, "%s\n", gPsCmd[PS_ADD]);
6079 }
6080 x += pStrBlock->w;
6081 }
6082 if (!do_dump) {
6083 DumpIndentString(FP, indent);
6084 fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
6085 }
6086 }
6087
DumpMiniLines(minilines,x,baseline_y,FP,pBBox,do_dump,indent)6088 void DumpMiniLines(minilines, x, baseline_y, FP, pBBox, do_dump, indent)
6089 MiniLinesInfo *minilines;
6090 int x, baseline_y, do_dump, indent;
6091 FILE *FP;
6092 struct BBRec *pBBox;
6093 /*
6094 * x is the origin of the minilines (not the left edge)
6095 */
6096 {
6097 MiniLineInfo *pMiniLine=NULL;
6098 int v_space=minilines->v_space, just=minilines->just;
6099 int saved_x=x;
6100
6101 if (!do_dump) {
6102 /*
6103 * compute the max of the widths and leave it on the stop of stack
6104 */
6105 DumpIndentString(FP, indent);
6106 fprintf(FP, "0\n");
6107 }
6108 for (pMiniLine=minilines->first; pMiniLine != NULL;
6109 pMiniLine=pMiniLine->next) {
6110 baseline_y += pMiniLine->v_gap;
6111 if (do_dump && pMiniLine->v_gap != 0) {
6112 DumpIndentString(FP, indent);
6113 fprintf(FP, "0 %1d %s\n", pMiniLine->v_gap, gPsCmd[PS_RMOVETO]);
6114 }
6115 DumpGSave(FP, do_dump, indent);
6116
6117 if (do_dump) {
6118 switch (just) {
6119 case JUST_L:
6120 DumpMiniLine(pMiniLine, saved_x, baseline_y, FP, pBBox, TRUE,
6121 indent+2);
6122 break;
6123 case JUST_C:
6124 case JUST_R:
6125 /* get the length of the string on top of the stack */
6126 DumpMiniLine(pMiniLine, x, baseline_y, FP, pBBox, FALSE, indent+2);
6127 DumpIndentString(FP, indent);
6128 if (just == JUST_C) {
6129 fprintf(FP, "2 %s %s 0 %s\n", gPsCmd[PS_DIV], gPsCmd[PS_NEG],
6130 gPsCmd[PS_RMOVETO]);
6131 } else {
6132 fprintf(FP, "%s 0 %s\n", gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
6133 }
6134 /* now dump it */
6135 DumpMiniLine(pMiniLine, x, baseline_y, FP, pBBox, TRUE, indent+2);
6136 break;
6137 }
6138 } else {
6139 DumpMiniLine(pMiniLine, x, baseline_y, FP, pBBox, FALSE, indent+2);
6140 DumpIndentString(FP, indent);
6141 fprintf(FP, "TGMAX\n");
6142 }
6143 DumpGRestore(FP, do_dump, indent);
6144
6145 if (pMiniLine->next != NULL) {
6146 baseline_y += pMiniLine->des + v_space + pMiniLine->next->asc;
6147 if (do_dump && (pMiniLine->des+v_space+pMiniLine->next->asc) != 0) {
6148 DumpIndentString(FP, indent);
6149 fprintf(FP, "0 %1d %s\n",
6150 (pMiniLine->des+v_space+pMiniLine->next->asc),
6151 gPsCmd[PS_RMOVETO]);
6152 }
6153 }
6154 }
6155 }
6156
6157 /* --------------------- DumpSimpleTextPath() --------------------- */
6158
SimpleTextObj(text_ptr)6159 int SimpleTextObj(text_ptr)
6160 struct TextRec *text_ptr;
6161 {
6162 MiniLinesInfo *minilines=(&text_ptr->minilines);
6163 MiniLineInfo *pMiniLine=minilines->first;
6164 StrBlockInfo *pStrBlock=NULL;
6165
6166 if (text_ptr->fill == NONEPAT) {
6167 /*
6168 * Return FALSE here does not mean that the text object is simple.
6169 *
6170 * Since there is no fill, there is no need to measure the width of
6171 * text in this case. Therefore, return FALSE;
6172 */
6173 return FALSE;
6174 }
6175 if (pMiniLine != minilines->last) return FALSE;
6176
6177 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
6178 pStrBlock=pStrBlock->next) {
6179 if (pStrBlock->type != SB_SIMPLE) return FALSE;
6180 }
6181 return TRUE;
6182 }
6183
DumpSimpleTextPath(FP,ObjPtr)6184 void DumpSimpleTextPath(FP, ObjPtr)
6185 FILE *FP;
6186 struct ObjRec *ObjPtr;
6187 {
6188 struct TextRec *text_ptr=ObjPtr->detail.t;
6189 MiniLinesInfo *minilines=(&text_ptr->minilines);
6190 MiniLineInfo *pMiniLine=minilines->first;
6191 StrBlockInfo *pStrBlock=NULL;
6192
6193 #ifdef _TGIF_DBG /* debug, do not translate */
6194 TgAssert(SimpleTextObj(text_ptr),
6195 "Text is not a simple text object in DumpSimpleTextPath()", NULL);
6196 #endif /* _TGIF_DBG */
6197
6198 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
6199 pStrBlock=pStrBlock->next) {
6200 fprintf(FP, " /tgifstrw tgifstrw\n");
6201 DumpStrSeg(pStrBlock->seg, JUST_L, 0, 0, FP, &ObjPtr->obbox, FALSE, 6);
6202 fprintf(FP, " add def\n");
6203 }
6204 }
6205
6206 /* --------------------- DumpMiniLinesInAscii() --------------------- */
6207
6208 static
DumpStrSegInAscii(FP,pStrSeg,pnSomethingPrinted)6209 void DumpStrSegInAscii(FP, pStrSeg, pnSomethingPrinted)
6210 FILE *FP;
6211 StrSegInfo *pStrSeg;
6212 int *pnSomethingPrinted;
6213 {
6214 if (*pStrSeg->dyn_str.s == '\0') return;
6215
6216 if (fprintf(FP, "%s", pStrSeg->dyn_str.s) == EOF) {
6217 writeFileFailed = TRUE;
6218 }
6219 if (pnSomethingPrinted != NULL) *pnSomethingPrinted = TRUE;
6220 }
6221
6222 static
DumpStrBlockInAscii(FP,pStrBlock,pnSomethingPrinted)6223 void DumpStrBlockInAscii(FP, pStrBlock, pnSomethingPrinted)
6224 FILE *FP;
6225 StrBlockInfo *pStrBlock;
6226 int *pnSomethingPrinted;
6227 {
6228 switch (pStrBlock->type) {
6229 case SB_SIMPLE:
6230 DumpStrSegInAscii(FP, pStrBlock->seg, pnSomethingPrinted);
6231 break;
6232
6233 case SB_CHAR_SPACE:
6234 if (fprintf(FP, " ") == EOF) writeFileFailed = TRUE;
6235 break;
6236
6237 case SB_SUPSUB_LEFT:
6238 case SB_SUPSUB_CENTER:
6239 case SB_SUPSUB_RIGHT:
6240 fprintf(FP, "\n");
6241 if (pStrBlock->type == SB_SUPSUB_CENTER) {
6242 /* pStrBlock->seg better not be NULL or it will crash */
6243 DumpStrSegInAscii(FP, pStrBlock->seg, pnSomethingPrinted);
6244 if (fprintf(FP, "\n") == EOF) writeFileFailed = TRUE;
6245 }
6246 if (pStrBlock->sup != NULL) {
6247 if (!BlankMiniLines(pStrBlock->sup)) {
6248 DumpMiniLinesInAscii(FP, pStrBlock->sup, pnSomethingPrinted);
6249 }
6250 }
6251 if (pStrBlock->sub != NULL) {
6252 if (!BlankMiniLines(pStrBlock->sub)) {
6253 DumpMiniLinesInAscii(FP, pStrBlock->sub, pnSomethingPrinted);
6254 }
6255 }
6256 break;
6257 }
6258 }
6259
DumpMiniLineInAscii(FP,pMiniLine,pnSomethingPrinted)6260 void DumpMiniLineInAscii(FP, pMiniLine, pnSomethingPrinted)
6261 FILE *FP;
6262 MiniLineInfo *pMiniLine;
6263 int *pnSomethingPrinted;
6264 {
6265 StrBlockInfo *pStrBlock=NULL;
6266
6267 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
6268 pStrBlock=pStrBlock->next) {
6269 DumpStrBlockInAscii(FP, pStrBlock, pnSomethingPrinted);
6270 }
6271 }
6272
DumpMiniLinesInAscii(FP,minilines,pnSomethingPrinted)6273 void DumpMiniLinesInAscii(FP, minilines, pnSomethingPrinted)
6274 FILE *FP;
6275 MiniLinesInfo *minilines;
6276 int *pnSomethingPrinted;
6277 {
6278 MiniLineInfo *pMiniLine=NULL;
6279
6280 for (pMiniLine=minilines->first; pMiniLine != NULL;
6281 pMiniLine=pMiniLine->next) {
6282 DumpMiniLineInAscii(FP, pMiniLine, pnSomethingPrinted);
6283 if (fprintf(FP, "\n") == EOF) writeFileFailed = TRUE;
6284 }
6285 }
6286
6287 /* --------------------- ConvertMiniLineToString() --------------------- */
6288
6289 static
ConvertStrSegToString(pStrSeg,ppsz_buf,pn_len)6290 void ConvertStrSegToString(pStrSeg, ppsz_buf, pn_len)
6291 StrSegInfo *pStrSeg;
6292 char **ppsz_buf;
6293 int *pn_len;
6294 {
6295 int len=0;
6296
6297 if (*pStrSeg->dyn_str.s == '\0') return;
6298
6299 len = strlen(pStrSeg->dyn_str.s);
6300 (*ppsz_buf) = realloc(*ppsz_buf, ((*pn_len)+len+1)*sizeof(char));
6301 if ((*ppsz_buf) == NULL) FailAllocMessage();
6302 strcpy(&(*ppsz_buf)[*pn_len], pStrSeg->dyn_str.s);
6303 *pn_len += len;
6304 }
6305
6306 static
ConvertStrBlockToString(pStrBlock,ppsz_buf,pn_len)6307 int ConvertStrBlockToString(pStrBlock, ppsz_buf, pn_len)
6308 StrBlockInfo *pStrBlock;
6309 char **ppsz_buf;
6310 int *pn_len;
6311 /* returns TRUE to continue to the next block */
6312 /* returns FALSE if this string block contains super/subscripts */
6313 {
6314 switch (pStrBlock->type) {
6315 case SB_SIMPLE:
6316 ConvertStrSegToString(pStrBlock->seg, ppsz_buf, pn_len);
6317 break;
6318
6319 case SB_CHAR_SPACE:
6320 if (pStrBlock->special_char_w > 0) {
6321 /* only generate a space if the width of the thin space is > 0 */
6322 (*ppsz_buf) = realloc(*ppsz_buf, ((*pn_len)+2)*sizeof(char));
6323 if ((*ppsz_buf) == NULL) FailAllocMessage();
6324 strcpy(&(*ppsz_buf)[*pn_len], " ");
6325 (*pn_len)++;
6326 }
6327 break;
6328
6329 case SB_SUPSUB_LEFT:
6330 case SB_SUPSUB_CENTER:
6331 case SB_SUPSUB_RIGHT:
6332 if (!BlankMiniLines(pStrBlock->sup) || !BlankMiniLines(pStrBlock->sub)) {
6333 return FALSE;
6334 }
6335 if (pStrBlock->type == SB_SUPSUB_CENTER) {
6336 /* pStrBlock->seg better not be NULL or it will crash */
6337 ConvertStrSegToString(pStrBlock->seg, ppsz_buf, pn_len);
6338 }
6339 break;
6340 }
6341 return TRUE;
6342 }
6343
ConvertMiniLineToString(pMiniLine,pnNeedToFree)6344 char *ConvertMiniLineToString(pMiniLine, pnNeedToFree)
6345 MiniLineInfo *pMiniLine;
6346 int *pnNeedToFree;
6347 /* must free the returned string with UtilFree() */
6348 {
6349 char *buf=NULL;
6350 int len=0;
6351 StrBlockInfo *pStrBlock=NULL;
6352
6353 *pnNeedToFree = FALSE;
6354 if (pMiniLine->first_block->next == NULL) {
6355 return pMiniLine->first_block->seg->dyn_str.s;
6356 }
6357 buf = UtilStrDup(pMiniLine->first_block->seg->dyn_str.s);
6358 if (buf == NULL) FailAllocMessage();
6359 len = strlen(buf);
6360 for (pStrBlock=pMiniLine->first_block->next; pStrBlock != NULL;
6361 pStrBlock=pStrBlock->next) {
6362 if (!ConvertStrBlockToString(pStrBlock, &buf, &len)) {
6363 break;
6364 }
6365 }
6366 *pnNeedToFree = TRUE;
6367
6368 return buf;
6369 }
6370
6371 /* ----------------- ConvertAttrNameFirstMiniLineToString() ----------------- */
6372
ConvertAttrNameFirstMiniLineToString(attr_ptr,pnNeedToFree)6373 char *ConvertAttrNameFirstMiniLineToString(attr_ptr, pnNeedToFree)
6374 struct AttrRec *attr_ptr;
6375 int *pnNeedToFree; /* must not be NULL */
6376 /* must free the returned string with UtilFree() */
6377 {
6378 char *tmp_buf=NULL;
6379
6380 tmp_buf = ConvertMiniLineToString(attr_ptr->obj->detail.t->minilines.first,
6381 pnNeedToFree);
6382 if (*attr_ptr->attr_name.s != '\0' && !attr_ptr->nameshown) {
6383 char *psz=(char*)malloc(sizeof(char) *
6384 (attr_ptr->attr_name.sz+strlen(tmp_buf)));
6385
6386 if (psz == NULL) FailAllocMessage();
6387 sprintf(psz, "%s%s", attr_ptr->attr_name.s, tmp_buf);
6388 if (*pnNeedToFree) UtilFree(tmp_buf);
6389 tmp_buf = psz;
6390 *pnNeedToFree = TRUE;
6391 }
6392 return tmp_buf;
6393 }
6394
6395 /* ----------------- MiniLinesInVisibleLayer() ----------------- */
6396
6397 static
StrSegInVisibleLayer(pStrSeg)6398 int StrSegInVisibleLayer(pStrSeg)
6399 StrSegInfo *pStrSeg;
6400 {
6401 return colorLayerOn[pStrSeg->color];
6402 }
6403
6404 static
StrBlockInVisibleLayer(pStrBlock)6405 int StrBlockInVisibleLayer(pStrBlock)
6406 StrBlockInfo *pStrBlock;
6407 {
6408 switch (pStrBlock->type) {
6409 case SB_SIMPLE: return StrSegInVisibleLayer(pStrBlock->seg);
6410 case SB_CHAR_SPACE: return FALSE;
6411
6412 case SB_SUPSUB_LEFT:
6413 case SB_SUPSUB_CENTER:
6414 case SB_SUPSUB_RIGHT:
6415 if (pStrBlock->type == SB_SUPSUB_CENTER) {
6416 if (StrSegInVisibleLayer(pStrBlock->seg)) {
6417 return TRUE;
6418 }
6419 }
6420 if (pStrBlock->sup != NULL) {
6421 if (MiniLinesInVisibleLayer(pStrBlock->sup)) {
6422 return TRUE;
6423 }
6424 }
6425 if (pStrBlock->sub != NULL) {
6426 if (MiniLinesInVisibleLayer(pStrBlock->sub)) {
6427 return TRUE;
6428 }
6429 }
6430 break;
6431 }
6432 return FALSE;
6433 }
6434
6435 static
MiniLineInVisibleLayer(pMiniLine)6436 int MiniLineInVisibleLayer(pMiniLine)
6437 MiniLineInfo *pMiniLine;
6438 {
6439 StrBlockInfo *pStrBlock=NULL;
6440
6441 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
6442 pStrBlock=pStrBlock->next) {
6443 if (StrBlockInVisibleLayer(pStrBlock)) {
6444 return TRUE;
6445 }
6446 }
6447 return FALSE;
6448 }
6449
MiniLinesInVisibleLayer(minilines)6450 int MiniLinesInVisibleLayer(minilines)
6451 MiniLinesInfo *minilines;
6452 {
6453 MiniLineInfo *pMiniLine=NULL;
6454
6455 for (pMiniLine=minilines->first; pMiniLine != NULL;
6456 pMiniLine=pMiniLine->next) {
6457 if (MiniLineInVisibleLayer(pMiniLine)) {
6458 return TRUE;
6459 }
6460 }
6461 return FALSE;
6462 }
6463
6464