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