Re: crash on importing RTF


Subject: Re: crash on importing RTF
From: Martin Sevior (msevior@mccubbin.ph.unimelb.edu.au)
Date: Sat Dec 02 2000 - 20:51:49 CST


On Thu, 30 Nov 2000, Mike Nordell wrote:

> On importing a moderately large RTF file (about 7.2MB :-) ) I found an
> "interesting behaviour.
>
> The constructor for FL_DocLayout tries to add a new listener to the
> document. PD_Document forwards this request to its pt_PieceTable. All well
> so far. But then pt_PieceTable::addListener calls
> pt_PieceTable::_tellAndMaybeAddListener which creates a SpecialChangeRecord.
> Now *this* is a mystery to me why it should want to add a change record for
> adding a listener. Perhaps it's by design, I dunno. Is adding a listener an
> undoable operation?

<This is a long email but I think it contains some valuable information
not present in Sam's collection of Abiword Documents.>

HI Mike,
        I had a brief look at the code you mentioned. Adding a listener in
the constructor is the process of adding a view to the document. You can't
have a document without a view. The special change record is
needed to initialize the new view. See later.

>
> Well, fl_DocListener::populate

The change record is the signal to build the Layout structure from the
Piece Table.

As far as I've been able to figure out the abiword overview is something
like this. (Excuse the ascii art, one day I'll do a proper picture)

Frame Frame Frame
fv_View fv_View fv_View
fl_layout fl_layout fl_Layout
fl_docListner fl_docListner fl_docListner
\ | /
  \ | /
    \ | /
      \ | /
        \ | /
         \ | /
        pd_Document <------> import/exporter
            ||
            ||
        pt_PieceTable pt_PieceTable pt_PieceTable
             \ | /
              \ | /
               \ | /
                \ | /
                 \ | /
                  \ | /
                   \ | /
                    \ | /
                     XAP_App

So pd_Document is the controller in the model-view-controller
paradim. fv_View operations can modify the piece table through calls to
pd_Document. These changes are then reflected in all views (or
layouts) attached to the document. These are
implemented as a vector of (void *) pointers in pd_Docment which point to
to the fl_DocListener(s). Each fl_DocListener only knows about their own
Layout's and it is the job of fl_DocListener to update a layout (or view)
for every change in the piece table.

Population is the act of filling the layout with actual data. Now as
I recall the way a paragraph is actually built is by stuffing everything
in a span onto a single line via _stuffAllRunsOnALine() in fl_BlockLayout
then let the line breaking code workout how to actually position the text
within the layout. There may be bugs in this process but I haven't had the
time to work out what bugs are present and exactly how to trigger them.
Just doing this would be an enormous help. We have problems with our
importer which I've plastered over by judicous use of
fl_BlockLayout()->format() which appears to fix most errors in the intial
population of layout structures.

> gets called, and we get a span populated and
> an attempt to insert a forced linebreak (!) which forces a call to
> fp_Line::layout and it ends up in fp_Line::calculateWidthOfLine where the
> assert
> UT_ASSERT(iX <= m_iMaxWidth);
> triggers.
>

I've seen plenty of these asserts during imports but abi manages to
recover and import correctly. In your example if you continue past this
assert do you see a crash?

> I'm completely at loss here, since I couldn't ever dream of this call chain
> taking place just because someone wanted to add a listener. I'd think it
> would be a s simle as
> m_collection.add(pListener);
> but apparently I'm really ignorant in this area or something is badly broken
> with the semantics of this call. I'd like to think the latter. Whatever,
> it's a crash and I haven't got a clue where to begin to look for errors.
>

The act of attaching the listener to the pd_Document
requires some additional transfer of information from pd_Document to the
layout strcuture being built. At the very least each section and paragraph
in the layout has to know where in the pieceTable the data corresponding
to the section and paragraph actually is. These are stored as protected
member variables in the layout class. In particular

PL_StruxDocHandle m_sdh

which is stored in the fl_Layout.cpp baseclass,

is actually a (void *) pointer to the class in the Piece Table that
actually contains the data presented in the layout structure.

The callback "populate_span" absolutely necessary so that these pointers
can be stored in the layout.

OK That was a long answer to your question but it has taken me a long time
to understand all this about the sructure of AbiWord. Hopefully I've
explained it well enough that others don't have to spend the amount of
time I did working all this out.

Good Luck!

Martin



This archive was generated by hypermail 2b25 : Sat Dec 02 2000 - 20:51:57 CST