1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2
3 /* AbiWord
4 * Copyright (C) 1998 AbiSource, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA.
20 */
21
22 #include <ctype.h>
23 #include "ut_types.h"
24 #include "ut_misc.h"
25 #include "ut_string.h"
26 #include "ut_assert.h"
27 #include "ut_debugmsg.h"
28 #include "ut_growbuf.h"
29 #include "pt_PieceTable.h"
30 #include "pf_Frag.h"
31 #include "pf_Frag_Object.h"
32 #include "pf_Frag_FmtMark.h"
33 #include "pf_Frag_Strux.h"
34 #include "pf_Frag_Strux_Block.h"
35 #include "pf_Frag_Strux_Section.h"
36 #include "pf_Frag_Text.h"
37 #include "pf_Fragments.h"
38 #include "px_ChangeRecord.h"
39 #include "px_CR_Span.h"
40 #include "px_CR_SpanChange.h"
41 #include "px_CR_Strux.h"
42
43 /****************************************************************/
44 /****************************************************************/
45
appendStrux(PTStruxType pts,const gchar ** attributes,pf_Frag_Strux ** ppfs_ret)46 bool pt_PieceTable::appendStrux(PTStruxType pts, const gchar ** attributes, pf_Frag_Strux ** ppfs_ret)
47 {
48 pf_Frag_Strux * pfs = NULL;
49 if(!_makeStrux(pts, attributes, pfs) || !pfs)
50 return false;
51
52 if(attributes)
53 {
54 const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
55 UT_uint32 iXID = 0;
56 if(pXID && *pXID)
57 {
58 iXID = atoi(pXID);
59 pfs->setXID(iXID);
60 }
61 }
62
63 pf_Frag * pfPrev = m_fragments.getLast();
64 bool bDoInsertFmt = false;
65 if(pfPrev != NULL && pfPrev->getType() == pf_Frag::PFT_Strux)
66 {
67 pf_Frag_Strux * pfsPrev = static_cast<pf_Frag_Strux *>(pfPrev);
68 if(pfsPrev->getStruxType() == PTX_Block)
69 {
70 bDoInsertFmt = true;
71 }
72 }
73 m_fragments.appendFrag(pfs);
74 // insert frag in the embedded_strux list if needed
75 if ((pts == PTX_EndFootnote) || (pts == PTX_EndEndnote) || (pts == PTX_EndAnnotation))
76 {
77 _insertNoteInEmbeddedStruxList(pfs);
78 }
79
80 if(bDoInsertFmt)
81 {
82 insertFmtMarkBeforeFrag(static_cast<pf_Frag *>(pfs));
83 }
84 if (ppfs_ret)
85 *ppfs_ret = pfs;
86 return true;
87 }
88
89 /**
90 * MIQ11: Extends the old _findLastStruxOfType adding a stopCondition
91 * for failure and returning a Strux* directly in the case of success.
92 * This is like a findBackwards() from a fragment.
93 *
94 * stopConditions must be terminated with a PTX_StruxDummy entry like:
95 * PTStruxType stopCondition[] = { PTX_SectionTable, PTX_StruxDummy };
96 *
97 * Find a fragment of strux type pst looking backwards from pfStart.
98 * If a strux fragment matching the stopCondition is found first then
99 * the function stops and returns 0. If no fragment with pst is found
100 * then 0 is returned.
101 *
102 * MAYBE: extend this again to take yes() and no() functors so a
103 * function can call _findLastStruxOfType() and decide what is ok
104 * and what is not using those.
105 * boost::lambda would be handy to simplify the functors?
106 */
_findLastStruxOfType(pf_Frag * pfStart,PTStruxType pst,PTStruxType * stopConditions,bool bSkipEmbededSections)107 pf_Frag_Strux* pt_PieceTable::_findLastStruxOfType( pf_Frag * pfStart,
108 PTStruxType pst,
109 PTStruxType* stopConditions,
110 bool bSkipEmbededSections )
111 {
112 UT_return_val_if_fail( pfStart, NULL );
113
114 pf_Frag * pf = pfStart;
115 PTStruxType* stopConditionsBegin = stopConditions;
116 PTStruxType* stopConditionsEnd = stopConditions;
117 while( *stopConditionsEnd != PTX_StruxDummy )
118 ++stopConditionsEnd;
119
120 while(pf)
121 {
122 if(pf->getType() == pf_Frag::PFT_Strux)
123 {
124 pf_Frag_Strux * pfs2 = static_cast<pf_Frag_Strux*>(pf);
125
126 PTStruxType eStruxType = pfs2->getStruxType();
127
128 if( eStruxType == pst)
129 return pfs2;
130
131 if( stopConditionsEnd !=
132 std::find( stopConditionsBegin, stopConditionsEnd, eStruxType ))
133 {
134 return 0;
135 }
136
137 if(bSkipEmbededSections)
138 {
139 if(pfs2->getStruxType() == PTX_EndTOC)
140 {
141 while(pf)
142 {
143 if(pf->getType() == pf_Frag::PFT_Strux)
144 {
145 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
146
147 if(pfs->getStruxType() == PTX_SectionTOC)
148 break;
149 }
150
151 pf = pf->getPrev();
152 }
153 }
154 if(pfs2->getStruxType() == PTX_EndFrame)
155 {
156 while(pf)
157 {
158 if(pf->getType() == pf_Frag::PFT_Strux)
159 {
160 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
161
162 if(pfs->getStruxType() == PTX_SectionFrame)
163 break;
164 }
165
166 pf = pf->getPrev();
167 }
168 }
169
170 if(pfs2->getStruxType() == PTX_EndEndnote)
171 {
172 while(pf)
173 {
174 if(pf->getType() == pf_Frag::PFT_Strux)
175 {
176 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
177
178 if(pfs->getStruxType() == PTX_SectionEndnote)
179 break;
180 }
181
182 pf = pf->getPrev();
183 }
184 }
185 if(pfs2->getStruxType() == PTX_EndFootnote)
186 {
187 while(pf)
188 {
189 if(pf->getType() == pf_Frag::PFT_Strux)
190 {
191 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
192
193 if(pfs->getStruxType() == PTX_SectionFootnote)
194 break;
195 }
196
197 pf = pf->getPrev();
198 }
199 }
200 if(pfs2->getStruxType() == PTX_EndMarginnote)
201 {
202 while(pf)
203 {
204 if(pf->getType() == pf_Frag::PFT_Strux)
205 {
206 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
207
208 if(pfs->getStruxType() == PTX_SectionMarginnote)
209 break;
210 }
211
212 pf = pf->getPrev();
213 }
214 }
215 }
216 }
217 if(pf)
218 pf = pf->getPrev();
219 }
220
221 return 0;
222 }
223
224
225
_findLastStruxOfType(pf_Frag * pfStart,PTStruxType pst,bool bSkipEmbededSections)226 pf_Frag_Strux* pt_PieceTable::_findLastStruxOfType( pf_Frag * pfStart,
227 PTStruxType pst,
228 bool bSkipEmbededSections )
229 {
230 UT_return_val_if_fail( pfStart, NULL );
231 PTStruxType stopCondition[] = { PTX_StruxDummy };
232 return _findLastStruxOfType( pfStart, pst, stopCondition, bSkipEmbededSections );
233 }
234
235
236 /*!
237 Changes formating of the last strux of type pts
238 bSkipEmbededSections indicates whether when an end of an embeded section is
239 encountered, the entire section is to be skipped over, for example if the end of the
240 document looks like
241
242 <p><footnote><p></p></footnote>
243
244 when searching for <p> if bSkipEmbededSections == true the paragraph before <footnote>
245 will be modified
246 */
appendLastStruxFmt(PTStruxType pst,const gchar ** attributes,const gchar ** props,bool bSkipEmbededSections)247 bool pt_PieceTable::appendLastStruxFmt(PTStruxType pst, const gchar ** attributes, const gchar ** props,
248 bool bSkipEmbededSections)
249 {
250 // can only be used while loading the document
251 UT_return_val_if_fail (m_pts==PTS_Loading,false);
252
253 // Only a strux can be appended to an empty document
254 UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
255 if (!m_fragments.getFirst())
256 return false;
257
258 pf_Frag * pf = m_fragments.getLast();
259
260 UT_return_val_if_fail ( pf, false );
261
262 pf = _findLastStruxOfType(pf, pst, bSkipEmbededSections);
263
264 UT_return_val_if_fail( pf, false );
265
266 PT_AttrPropIndex currentAP = pf->getIndexAP();
267
268 const PP_AttrProp * pOldAP;
269 if(!getAttrProp(currentAP,&pOldAP))
270 return false;
271
272 PP_AttrProp * pNewAP = pOldAP->cloneWithReplacements(attributes,props,false);
273 pNewAP->markReadOnly();
274
275 PT_AttrPropIndex indexAP;
276 if (!m_varset.addIfUniqueAP(pNewAP,&indexAP))
277 return false;
278
279 pf->setIndexAP(indexAP);
280
281 return true;
282 }
283
284 /*!
285 As above, but props represented by a single XML string
286
287 */
appendLastStruxFmt(PTStruxType pst,const gchar ** attributes,const gchar * props,bool bSkipEmbededSections)288 bool pt_PieceTable::appendLastStruxFmt(PTStruxType pst, const gchar ** attributes, const gchar * props,
289 bool bSkipEmbededSections)
290 {
291 if(props && *props)
292 {
293 // we parse the xml props string into separate field by simply duplicating it and then
294 // replacing ; and : with '0';
295
296 // foolproofing
297 if(*props == ';')
298 props++;
299
300 char * pProps = g_strdup(props);
301
302 const gchar ** pPropsArray = UT_splitPropsToArray(pProps);
303 UT_return_val_if_fail( pPropsArray, false );
304
305 bool bRet = appendLastStruxFmt(pst, attributes, pPropsArray, bSkipEmbededSections);
306
307 delete [] pPropsArray;
308 FREEP(pProps);
309
310 return bRet;
311 }
312 else
313 {
314 const gchar ** pPropsArray = NULL;
315 return appendLastStruxFmt(pst, attributes, pPropsArray, bSkipEmbededSections);
316 }
317 }
318
319 /*! changes formatting of a strux while loading document */
appendStruxFmt(pf_Frag_Strux * pfs,const gchar ** attributes)320 bool pt_PieceTable::appendStruxFmt(pf_Frag_Strux * pfs, const gchar ** attributes)
321 {
322 // can only be used while loading the document
323 UT_return_val_if_fail (m_pts==PTS_Loading,false);
324
325 // Only a strux can be appended to an empty document
326 UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
327 if (!m_fragments.getFirst())
328 return false;
329
330 UT_return_val_if_fail ( pfs, false );
331
332 PT_AttrPropIndex currentAP = pfs->getIndexAP();
333
334 const PP_AttrProp * pOldAP;
335 if(!getAttrProp(currentAP,&pOldAP))
336 return false;
337
338 PP_AttrProp * pNewAP = pOldAP->cloneWithReplacements(attributes,NULL,true);
339 pNewAP->markReadOnly();
340
341 PT_AttrPropIndex indexAP;
342 if (!m_varset.addIfUniqueAP(pNewAP,&indexAP))
343 return false;
344
345 pfs->setIndexAP(indexAP);
346
347 return true;
348 }
349
appendFmt(const gchar ** attributes)350 bool pt_PieceTable::appendFmt(const gchar ** attributes)
351 {
352 // can only be used while loading the document
353 UT_return_val_if_fail (m_pts==PTS_Loading, false);
354
355 // Only a strux can be appended to an empty document
356 UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
357
358 // create a new Attribute/Property structure in the table
359 // and set the current index to it. the next span of text
360 // (in this block) that comes in will then be set to these
361 // attributes/properties. becase we are loading, we do not
362 // create a Fragment or a ChangeRecord. (Formatting changes
363 // are implicit at this point in time.)
364
365
366 if (!m_varset.storeAP(attributes,&loading.m_indexCurrentInlineAP))
367 return false;
368
369 return true;
370 }
371
appendFmt(const UT_GenericVector<const gchar * > * pVecAttributes)372 bool pt_PieceTable::appendFmt(const UT_GenericVector<const gchar*> * pVecAttributes)
373 {
374 // can only be used while loading the document
375 UT_return_val_if_fail (m_pts==PTS_Loading, false);
376
377 // Only a strux can be appended to an empty document
378 UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
379
380 if (!m_varset.storeAP(pVecAttributes,&loading.m_indexCurrentInlineAP))
381 return false;
382
383 return true;
384 }
385
appendSpan(const UT_UCSChar * pbuf,UT_uint32 length)386 bool pt_PieceTable::appendSpan(const UT_UCSChar * pbuf, UT_uint32 length)
387 {
388 // can only be used while loading the document
389 UT_return_val_if_fail (m_pts==PTS_Loading, false);
390
391 // Only a strux can be appended to an empty document
392 UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
393
394 // append the text data to the end of the buffer.
395
396 PT_BufIndex bi;
397 if (!m_varset.appendBuf(pbuf,length,&bi))
398 return false;
399
400 // set the formatting Attributes/Properties to that
401 // of the last fmt set in this paragraph.
402
403 // see if this span can be appended to the previous fragment
404 // (perhaps the parser was a bit lazy in chunking up the data).
405
406 pf_Frag * pfLast = m_fragments.getLast();
407 if ((pfLast != NULL) && (pfLast->getType() == pf_Frag::PFT_Text))
408 {
409 pf_Frag_Text * pfLastText = static_cast<pf_Frag_Text *>(pfLast);
410 if ( (pfLastText->getIndexAP() == loading.m_indexCurrentInlineAP)
411 && m_varset.isContiguous(pfLastText->getBufIndex(),pfLastText->getLength(),bi))
412 {
413 pfLastText->changeLength(pfLastText->getLength() + length);
414 return true;
415 }
416 }
417
418 // could not coalesce, so create a new fragment for this text span.
419
420 pf_Frag_Text * pft = new pf_Frag_Text(this,bi,length,loading.m_indexCurrentInlineAP,NULL);
421 if (!pft)
422 return false;
423
424 m_fragments.appendFrag(pft);
425
426 // because we are loading, we do not create change
427 // records or any of the other stuff that an insertSpan
428 // would do.
429
430 return true;
431 }
432
appendObject(PTObjectType pto,const gchar ** attributes)433 bool pt_PieceTable::appendObject(PTObjectType pto, const gchar ** attributes)
434 {
435 pf_Frag_Object * pfo = NULL;
436 if(!_makeObject(pto,attributes,pfo) || !pfo)
437 return false;
438
439 if(attributes)
440 {
441 const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
442 UT_uint32 iXID = 0;
443 if(pXID && *pXID)
444 {
445 iXID = atoi(pXID);
446 pfo->setXID(iXID);
447 }
448 }
449
450 m_fragments.appendFrag(pfo);
451 return true;
452 }
453
appendFmtMark(void)454 bool pt_PieceTable::appendFmtMark(void)
455 {
456 pf_Frag_FmtMark * pff = NULL;
457 if (!_makeFmtMark(pff) || !pff)
458 return false;
459
460 m_fragments.appendFrag(pff);
461 return true;
462 }
463
insertStruxBeforeFrag(pf_Frag * pF,PTStruxType pts,const gchar ** attributes,pf_Frag_Strux ** ppfs_ret)464 bool pt_PieceTable::insertStruxBeforeFrag(pf_Frag * pF, PTStruxType pts,
465 const gchar ** attributes, pf_Frag_Strux ** ppfs_ret)
466 {
467 UT_return_val_if_fail(pF , false);
468
469 pf_Frag_Strux * pfs = NULL;
470 if(!_makeStrux(pts, attributes, pfs) || !pfs)
471 return false;
472
473 if(attributes)
474 {
475 const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
476 UT_uint32 iXID = 0;
477 if(pXID && *pXID)
478 {
479 iXID = atoi(pXID);
480 pfs->setXID(iXID);
481 }
482 }
483
484 m_fragments.insertFragBefore(pF, pfs);
485 if (ppfs_ret)
486 *ppfs_ret = pfs;
487 // insert frag in the embedded_strux list if needed
488 if ((pts == PTX_EndFootnote) || (pts == PTX_EndEndnote) || (pts == PTX_EndAnnotation))
489 {
490 _insertNoteInEmbeddedStruxList(pfs);
491 }
492
493 return true;
494 }
495
496
insertSpanBeforeFrag(pf_Frag * pf,const UT_UCSChar * p,UT_uint32 length)497 bool pt_PieceTable::insertSpanBeforeFrag(pf_Frag * pf, const UT_UCSChar * p, UT_uint32 length)
498 {
499 // can only be used while loading the document
500 UT_return_val_if_fail (m_pts==PTS_Loading, false);
501
502 // Only a strux can be appended to an empty document
503 UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
504
505 // cannot insert before first fragment (i.e., span cannot start a document)
506 UT_return_val_if_fail(pf && pf->getPrev() && pf != m_fragments.getFirst(), false);
507
508 // append the text to the buffer
509 PT_BufIndex bi;
510 if (!m_varset.appendBuf(p,length,&bi))
511 return false;
512
513 // update the fragment and/or the fragment list.
514 // return true if successful.
515
516 pf_Frag_Text * pft = NULL;
517
518 // see if the fragement before this one is a text frag ...
519 if (pf->getPrev()->getType() == pf_Frag::PFT_Text)
520 {
521 pft = static_cast<pf_Frag_Text *>(pf->getPrev());
522 }
523
524 if (pft)
525 {
526 // We have a text frag on the left. Try to coalesce this
527 // character data with an existing fragment.
528
529 if((pft->getIndexAP() == loading.m_indexCurrentInlineAP) &&
530 m_varset.isContiguous(pft->getBufIndex(),pft->getLength(),bi))
531 {
532 // new text is contiguous, we just update the length of this fragment.
533 pft->changeLength(pft->getLength()+length);
534
535 // see if this (enlarged) fragment is now contiguous with the
536 // one that follows -- it cannot be when we are appending
537 return true;
538 }
539 }
540
541 // new text is not contiguous on the left, we need to insert a new text
542 // fragment into the list. first we construct a new text fragment
543 // for the data that we inserted.
544
545 pf_Frag_Text * pftNew = new pf_Frag_Text(this,bi,length,loading.m_indexCurrentInlineAP,NULL);
546 if (!pftNew)
547 return false;
548
549 m_fragments.insertFragBefore(pf,pftNew);
550
551 // no need to check for the new frag being continguous with the
552 // one on its right -- it cannot be, since the insertion occured in
553 // oposite order than the fargments have in the buffer
554
555 return true;
556 }
557
insertObjectBeforeFrag(pf_Frag * pF,PTObjectType pto,const gchar ** attributes)558 bool pt_PieceTable::insertObjectBeforeFrag(pf_Frag * pF, PTObjectType pto,
559 const gchar ** attributes)
560 {
561 // cannot insert before first fragment
562 UT_return_val_if_fail(pF && pF->getPrev() && pF != m_fragments.getFirst(), false);
563
564 pf_Frag_Object * pfo = NULL;
565 if(!_makeObject(pto,attributes,pfo) || !pfo)
566 return false;
567
568 if(attributes)
569 {
570 const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
571 UT_uint32 iXID = 0;
572 if(pXID && *pXID)
573 {
574 iXID = atoi(pXID);
575 pfo->setXID(iXID);
576 }
577 }
578
579 m_fragments.insertFragBefore(pF, pfo);
580 return true;
581 }
582
insertFmtMarkBeforeFrag(pf_Frag * pF)583 bool pt_PieceTable::insertFmtMarkBeforeFrag(pf_Frag * pF)
584 {
585 // cannot insert before first fragment
586 UT_return_val_if_fail(pF && pF->getPrev() && pF != m_fragments.getFirst(), false);
587
588 pf_Frag_FmtMark * pff = NULL;
589 if (!_makeFmtMark(pff) || !pff)
590 return false;
591
592 m_fragments.insertFragBefore(pF, pff);
593 return true;
594 }
595
596
insertFmtMarkBeforeFrag(pf_Frag * pF,const gchar ** attributes)597 bool pt_PieceTable::insertFmtMarkBeforeFrag(pf_Frag * pF, const gchar ** attributes)
598 {
599 // cannot insert before first fragment
600 UT_return_val_if_fail(pF && pF->getPrev() && pF != m_fragments.getFirst(), false);
601
602 pf_Frag_FmtMark * pff = NULL;
603 if (!_makeFmtMark(pff,attributes) || !pff)
604 return false;
605
606 m_fragments.insertFragBefore(pF, pff);
607 return true;
608 }
609
_makeStrux(PTStruxType pts,const gchar ** attributes,pf_Frag_Strux * & pfs)610 bool pt_PieceTable::_makeStrux(PTStruxType pts, const gchar ** attributes, pf_Frag_Strux * &pfs)
611 {
612 // create a new structure fragment at the current end of the document.
613 // this function can only be called while loading the document.
614 UT_return_val_if_fail (m_pts==PTS_Loading, false);
615
616 // first, store the attributes and properties and get an index to them.
617
618 PT_AttrPropIndex indexAP;
619 if (!m_varset.storeAP(attributes,&indexAP))
620 return false;
621
622 //
623 // OK we've got to interogate attributes to determine what sort of section strux
624 // we have.
625 //
626 if((pts == PTX_Section) && (attributes != NULL))
627 {
628 const char * szStruxType = UT_getAttribute("type",attributes);
629 if(szStruxType)
630 {
631 if(strcmp(szStruxType,"header") == 0 ||
632 strcmp(szStruxType,"footer") == 0 ||
633 strcmp(szStruxType,"header-even") == 0 ||
634 strcmp(szStruxType,"footer-even") == 0 ||
635 strcmp(szStruxType,"header-first") == 0 ||
636 strcmp(szStruxType,"footer-first") == 0 ||
637 strcmp(szStruxType,"header-last") == 0 ||
638 strcmp(szStruxType,"footer-last") == 0)
639 {
640 pts = PTX_SectionHdrFtr;
641 }
642 }
643 }
644 if (!_createStrux(pts,indexAP,&pfs))
645 return false;
646
647 return true;
648 }
649
650
_makeObject(PTObjectType pto,const gchar ** attributes,pf_Frag_Object * & pfo)651 bool pt_PieceTable::_makeObject(PTObjectType pto, const gchar ** attributes, pf_Frag_Object * &pfo)
652 {
653 // create a new object fragment at the current end of the document.
654 // this function can only be called while loading the document.
655 UT_return_val_if_fail (m_pts==PTS_Loading, false);
656
657 // Only a strux can be appended to an empty document
658 UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
659
660 // first, store the attributes and properties and get an index to them.
661
662 PT_AttrPropIndex indexAP;
663 if (!m_varset.storeAP(attributes,&indexAP))
664 return false;
665
666 if (!_createObject(pto,indexAP,&pfo))
667 return false;
668
669 return true;
670 }
671
_makeFmtMark(pf_Frag_FmtMark * & pff)672 bool pt_PieceTable::_makeFmtMark(pf_Frag_FmtMark * &pff)
673 {
674 // this function can only be called while loading the document.
675 UT_return_val_if_fail (m_pts==PTS_Loading,false);
676
677 // Only a strux can be appended to an empty document
678 UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
679
680 pff = new pf_Frag_FmtMark(this,loading.m_indexCurrentInlineAP);
681 if (!pff)
682 return false;
683
684 return true;
685 }
686
687
_makeFmtMark(pf_Frag_FmtMark * & pff,const gchar ** attributes)688 bool pt_PieceTable::_makeFmtMark(pf_Frag_FmtMark * &pff, const gchar ** attributes)
689 {
690 // this function can only be called while loading the document.
691 UT_return_val_if_fail (m_pts==PTS_Loading,false);
692
693 // Only a strux can be appended to an empty document
694 UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
695 if(attributes == NULL)
696 {
697 return _makeFmtMark(pff);
698 }
699 PT_AttrPropIndex indexAP;
700 if (!m_varset.storeAP(attributes,&indexAP))
701 return false;
702
703 pff = new pf_Frag_FmtMark(this,indexAP);
704 if (!pff)
705 return false;
706
707 return true;
708 }
709