~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to filters/kword/msword-odf/graphicshandler.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2010-10-27 17:52:57 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101027175257-s04zqqk5bs8ckm9o
Tags: 1:2.2.83-0ubuntu1
* Merge with Debian git remaining changes:
 - Add build-deps on librcps-dev, opengtl-dev, libqtgtl-dev, freetds-dev,
   create-resources, libspnav-dev
 - Remove needless build-dep on libwv2-dev
 - koffice-libs recommends create-resources
 - krita recommends pstoedit
 - Keep our patches
* New upstream release 2.3 beta 3
  - Remove debian/patches fixed by upstream
  - Update install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
#include "graphicshandler.h"
23
23
#include "document.h"
 
24
#include "conversion.h"
24
25
 
25
 
#include <wv2/src/olestream.h>
26
26
#include <wv2/src/ms_odraw.h>
 
27
 
27
28
#include "generated/leinputstream.h"
28
29
#include "drawstyle.h"
 
30
#include "ODrawToOdf.h"
 
31
#include "pictures.h"
29
32
 
30
33
#include <KoStoreDevice.h>
31
34
#include <KoGenStyle.h>
32
35
#include <kdebug.h>
33
36
#include <kmimetype.h>
34
 
 
 
37
#include <QtGui/QColor>
 
38
#include <QByteArray>
35
39
 
36
40
using namespace wvWare;
37
41
using namespace MSO;
38
42
 
 
43
using Conversion::twipsToPt;
 
44
 
39
45
#define IMG_BUF_SIZE 2048L
40
46
 
41
47
 
42
 
KWordPictureHandler::KWordPictureHandler(Document* doc, KoXmlWriter* bodyWriter,
43
 
        KoXmlWriter* manifestWriter, KoStore* store, KoGenStyles* mainStyles)
44
 
        : QObject(), m_doc(doc), m_pictureCount(0), m_officeArtCount(0)
45
 
{
46
 
    kDebug(30513) ;
47
 
    m_bodyWriter = bodyWriter;
48
 
    m_manifestWriter = manifestWriter;
49
 
    m_store = store;
50
 
    m_mainStyles = mainStyles;
51
 
}
52
 
 
53
 
void KWordPictureHandler::setBodyWriter(KoXmlWriter* writer)
54
 
{
55
 
    m_bodyWriter = writer;
56
 
}
57
 
 
58
 
#ifdef IMAGE_IMPORT
59
 
 
60
 
void KWordPictureHandler::bitmapData(OLEImageReader& reader, SharedPtr<const Word97::PICF> /*picf*/)
61
 
{
62
 
    kDebug(30513) << "Bitmap data found ->>>>>>>>>>>>>>>>>>>>>>>>>>>>> size=" << reader.size();
63
 
 
64
 
}
65
 
 
66
 
void KWordPictureHandler::escherData(OLEImageReader& reader, SharedPtr<const Word97::PICF> picf, int type, wvWare::U32 pib)
67
 
{
68
 
    kDebug(30513) << "Escher data found";
69
 
 
70
 
    QString picName;
71
 
    ODTProcessing(&picName, picf, type, pib);
72
 
 
73
 
    if (m_pictureName.contains(pib)) {
74
 
        //image data already loaded once
75
 
        return;
76
 
    }
77
 
    else {
78
 
        //insert the picture name into hash table
79
 
        m_pictureName.insert(pib, picName);
80
 
 
81
 
        //write picture data to file
82
 
        m_store->open(picName);//open picture file
83
 
 
84
 
        long len = reader.size();
85
 
        while (len > 0)  {
86
 
            kDebug(30513) << "len = " << len;
87
 
            wvWare::U8* buf = new wvWare::U8[IMG_BUF_SIZE];
88
 
            size_t n = reader.read(buf, qMin(len, IMG_BUF_SIZE));
89
 
            long n1 = m_store->write((const char*)buf, n);
90
 
            kDebug(30513) << "n=" << n << ", n1=" << n1 << "; buf contains " << (void*) buf;
91
 
            len -= n;
92
 
            delete [] buf;
93
 
            //error checking
94
 
            if ((n == 0 && len != 0) ||  //endless loop
95
 
                (size_t)n1 != n) { //read/wrote different lengths
96
 
                 m_store->close(); //close picture file before returning
97
 
                 return; //ouch - we're in an endless loop!
98
 
            }
99
 
            //Q_ASSERT( (size_t)n1 == n );
100
 
        }
101
 
        Q_ASSERT(len == 0);
102
 
        m_store->close(); //close picture file
103
 
    }
104
 
}
105
 
 
106
 
//use this version when the data had to be decompressed
107
 
//so we don't have to convert the data back to an OLEImageReader
108
 
void KWordPictureHandler::escherData(std::vector<wvWare::U8> data, SharedPtr<const Word97::PICF> picf, int type, wvWare::U32 pib)
109
 
{
110
 
    kDebug(30513) << "Escher data found";
111
 
 
112
 
    QString picName;
113
 
    ODTProcessing(&picName, picf, type, pib);
114
 
 
115
 
    if (m_pictureName.contains(pib)) {
116
 
        //image data already loaded once
117
 
        return;
118
 
    }
119
 
    else {
120
 
        //insert the picture name into hash table
121
 
        m_pictureName.insert(pib, picName);
122
 
 
123
 
        //write picture data to file
124
 
        m_store->open(picName);//open picture file
125
 
 
126
 
        long len = data.size();
127
 
        int index = 0; //index for reading from vector
128
 
        while (len > 0)  {
129
 
            kDebug(30513) << "len = " << len;
130
 
            wvWare::U8* buf = new wvWare::U8[IMG_BUF_SIZE];
131
 
            //instead of a read command, we'll copy that number of bytes
132
 
            //from the vector into the buffer
133
 
            int n = qMin(len, IMG_BUF_SIZE);
134
 
            for (int i = 0; i < n; i++) {
135
 
                buf[i] = data[index];
136
 
                index++;
137
 
            }
138
 
            //size_t n = reader.read( buf, qMin( len, IMG_BUF_SIZE ) );
139
 
            long n1 = m_store->write((const char*)buf, n);
140
 
            kDebug(30513) << "n=" << n << ", n1=" << n1 << "; buf contains " << (void*) buf;
141
 
            len -= n;
142
 
            delete [] buf;
143
 
            //error checking
144
 
            if ((n == 0 && len != 0) ||  //endless loop
145
 
                (size_t)n1 != n) { //read/wrote different lengths
146
 
                m_store->close(); //close picture file before returning
147
 
                return; //ouch - we're in an endless loop!
148
 
            }
149
 
            //Q_ASSERT( (size_t)n1 == n );
150
 
          }
151
 
        Q_ASSERT(len == 0);
152
 
        m_store->close(); //close picture file
153
 
    }
154
 
}
155
 
 
156
 
void KWordPictureHandler::officeArt(wvWare::OfficeArtProperties *artProperties)
157
 
{
158
 
    if (artProperties->shapeType == msosptLine) {
159
 
        officeArtLine(artProperties);
160
 
    }
161
 
}
162
 
 
163
 
#endif // IMAGE_IMPORT
164
 
 
165
 
void KWordPictureHandler::officeArtLine(wvWare::OfficeArtProperties *artProperties)
166
 
{
167
 
    //TODO: properties like horizontal align should be applied to the picture,
168
 
    //but it has anchor type "as-char", let's check how to implement this.
169
 
 
170
 
    //Check if a picture is comming, this will be displayed instead of a line.
171
 
    if (artProperties->pib) {
172
 
        return;
173
 
    }
174
 
 
175
 
    QString hrAlign;
176
 
    QString xPos = QString::number(0.0f).append("in");
177
 
 
178
 
    switch (artProperties->align) {
179
 
        case wvWare::hAlignLeft:
180
 
                hrAlign = QString("left");
181
 
                xPos = QString::number(0.0f).append("in");
182
 
                break;
183
 
        case wvWare::hAlignCenter:
184
 
                hrAlign = QString("center");
185
 
                xPos = QString::number((6.1378f/2.0f) - ((artProperties->width * 6.1378f) / 200.0f)).append("in");
186
 
                break;
187
 
        case wvWare::hAlignRight:
188
 
                hrAlign = QString("right");
189
 
                xPos = QString::number(6.1378f - (artProperties->width * 6.1378f) / 100.0f).append("in");
190
 
                break;
191
 
    }
192
 
    m_officeArtCount++;
193
 
 
194
 
    // create a graphic style
195
 
    QString styleName("gr");
196
 
    styleName.append(QString::number(m_officeArtCount));
197
 
    KoGenStyle *style = new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic", "Graphics");
198
 
 
199
 
    //in case a header or footer is processed, save the style into styles.xml
200
 
    if (m_doc->writingHeader()) {
201
 
        style->setAutoStyleInStylesDotXml(true);
202
 
    }
203
 
 
204
 
    QString colorStr = QString("#%1%2%3").arg((int)artProperties->color.r, 2, 16, QChar('0')).arg((int)artProperties->color.g, 2, 16, QChar('0')).arg((int)artProperties->color.b, 2, 16, QChar('0'));
205
 
    style->addProperty("draw:fill","solid");
206
 
    style->addProperty("draw:fill-color", colorStr);
207
 
    style->addProperty("draw:textarea-horizontal-align",hrAlign);
208
 
    style->addProperty("draw:textarea-vertical-align","top");
209
 
    style->addProperty("draw:shadow","hidden");
210
 
    style->addProperty("style:run-through","foreground");
211
 
 
212
 
    styleName = m_mainStyles->insert(*style, styleName, KoGenStyles::DontAddNumberToName);    
213
 
 
214
 
    delete style;
215
 
    //--------------------
216
 
    // create a custom shape
217
 
    m_bodyWriter->startElement("draw:custom-shape");
218
 
    m_bodyWriter->addAttribute("text:anchor-type", "as-char");
219
 
 
220
 
    QString heightStr = QString::number(artProperties->height).append("in");
221
 
    m_bodyWriter->addAttribute("svg:height", heightStr);
222
 
 
223
 
    QString widthStr = QString::number((artProperties->width * 6.1378f) / 100.0f).append("in");
224
 
    m_bodyWriter->addAttribute("svg:width", widthStr);
225
 
    m_bodyWriter->addAttribute("svg:x", xPos);
226
 
    m_bodyWriter->addAttribute("draw:style-name", styleName.toUtf8());
227
 
 
228
 
    //--------------------
229
 
    m_bodyWriter->startElement("draw:enhanced-geometry");
230
 
    m_bodyWriter->addAttribute("svg:viewBox", "0 0 21600 21600");
231
 
    m_bodyWriter->addAttribute("draw:type", "rectangle");
232
 
    m_bodyWriter->addAttribute("draw:enhanced-path", "M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N");
233
 
    m_bodyWriter->endElement();
234
 
    //--------------------
235
 
    m_bodyWriter->endElement();                 // end draw:custom-shape
236
 
}
237
 
 
238
 
void KWordPictureHandler::ODTProcessing(QString* picName, SharedPtr<const Word97::PICF> picf, int type, wvWare::U32 pib)
239
 
  {
240
 
    //check if the referred pib is already in hash table
241
 
    //NOTE: the wmfData function has no pib to pass
242
 
    if (m_pictureName.contains(pib)) {
243
 
        picName->append(m_pictureName.value(pib));
244
 
    }
245
 
    else {
246
 
        //set up filename
247
 
        picName->append("Pictures/");
248
 
        picName->append(QString::number(m_pictureCount));
249
 
        m_pictureCount++;
250
 
        //the type coming in corresponds to MSOBLIPTYPE see wv2/src/graphics.h
251
 
        if (type == 5)
252
 
            picName->append(".jpg");
253
 
        else if (type == 6)
254
 
            picName->append(".png");
255
 
        else if (type == 3)
256
 
            picName->append(".wmf");
257
 
        else if (type == 2)
258
 
            picName->append(".emf");
259
 
        else {
260
 
            kWarning() << "Unhandled file type (" << type << ") - pictures won't be displayed.";
261
 
            return;
262
 
        }
263
 
        //add entry in manifest file
264
 
        QString mimetype(KMimeType::findByPath(*picName, 0, true)->name());
265
 
        m_manifestWriter->addManifestEntry(*picName, mimetype);
266
 
    }
267
 
    //create style
268
 
    QString styleName("fr");
269
 
    styleName.append(QString::number(m_pictureCount));
270
 
    KoGenStyle* style = new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic", "Graphics");
271
 
 
272
 
    //in case a header or footer is processed, save the style into styles.xml
273
 
    if (m_doc->writingHeader()) {
274
 
        style->setAutoStyleInStylesDotXml(true);
275
 
    }
276
 
 
277
 
    styleName = m_mainStyles->insert(*style, styleName, KoGenStyles::DontAddNumberToName);
278
 
    delete style;
279
 
 
280
 
    //start frame tag for the picture
281
 
    m_bodyWriter->startElement("draw:frame");
282
 
    m_bodyWriter->addAttribute("draw:style-name", styleName.toUtf8());
283
 
    m_bodyWriter->addAttribute("text:anchor-type", "as-char");
284
 
    //mx, my = horizontal & vertical user scaling in .001 %
285
 
    double horiz_scale = picf->mx / 1000.0;
286
 
    double vert_scale = picf->my / 1000.0;
287
 
    double height = ((double) picf->dyaGoal * vert_scale) / 20.0; //twips -> pt
288
 
    double width = ((double) picf->dxaGoal * horiz_scale) / 20.0; //twips -> pt
289
 
    m_bodyWriter->addAttributePt("svg:height", height);
290
 
    m_bodyWriter->addAttributePt("svg:width", width);
291
 
    //start the actual image tag
292
 
    m_bodyWriter->startElement("draw:image");
293
 
    m_bodyWriter->addAttribute("xlink:href", *picName);
294
 
    m_bodyWriter->addAttribute("xlink:type", "simple");
295
 
    m_bodyWriter->addAttribute("xlink:show", "embed");
296
 
    m_bodyWriter->addAttribute("xlink:actuate", "onLoad");
297
 
    m_bodyWriter->endElement();//draw:image
298
 
    m_bodyWriter->endElement();//draw:frame
299
 
}
300
 
 
301
 
void KWordPictureHandler::wmfData(OLEImageReader& reader, SharedPtr<const Word97::PICF> picf)
302
 
{
303
 
    wvWare::U8* buf = new wvWare::U8[IMG_BUF_SIZE];
304
 
 
305
 
    kDebug(30513) << "WMF data found. Size=" << reader.size();
306
 
 
307
 
    QString picName;
308
 
 
309
 
    // Read the first bytes of the picture.  We need this to determine
310
 
    // if the contents is a WMF or an EMF.
311
 
    long len = reader.size();
312
 
    size_t  n = reader.read(buf, qMin(len, IMG_BUF_SIZE));
313
 
 
314
 
    // Pass 2 for emf image and 3 for wmf image
315
 
    // An EMF has the string " EMF" at the start + offset 40.
316
 
    if (len > 44 && buf[40] == ' ' && buf[41] == 'E' && buf[42] == 'M' && buf[43] == 'F') {
317
 
        kDebug(30513) << "Found an EMF file";
318
 
        ODTProcessing(&picName, picf, 2, 0);
319
 
    }
320
 
    else {
321
 
        kDebug(30513) << "Found a WMF file";
322
 
        ODTProcessing(&picName, picf, 3, 0);
323
 
    }
324
 
 
325
 
    // Write picture data to file.
326
 
    m_store->open(picName);//open picture file
327
 
    while (len > 0)  {
328
 
        kDebug(30513) << "len = " << len;
329
 
 
330
 
        // Write the bytes that we have in the buffer.
331
 
        ulong    n1 = m_store->write((const char*)buf, n);
332
 
        kDebug(30513) << "n=" << n << ", n1=" << n1 << "; buf contains " << (void*) buf;
333
 
        len -= n;
334
 
 
335
 
        // Break if something went wrong with the writing.
336
 
        if (n1 != n)
337
 
            break;
338
 
 
339
 
        if (len == 0)
340
 
            break;
341
 
 
342
 
        // Read the next batch.
343
 
        size_t  n = reader.read(buf, qMin(len, IMG_BUF_SIZE));
344
 
 
345
 
        //error checking
346
 
        if (n == 0 && len != 0)
347
 
            break;
348
 
    }
349
 
 
350
 
    delete [] buf;
351
 
 
352
 
    m_store->close(); //close picture file
353
 
}
354
 
 
355
 
void KWordPictureHandler::externalImage(const UString& name, SharedPtr<const Word97::PICF> picf)
356
 
{
357
 
    kDebug(30513);
358
 
}
359
 
 
360
 
DrawingWriter::DrawingWriter(KoXmlWriter& xmlWriter, KoGenStyles& kostyles, bool stylesxml_)
361
 
        : Writer(xmlWriter,kostyles,stylesxml_),
362
 
        xLeft(0),
363
 
        xRight(0),
364
 
        yTop(0),
365
 
        yBottom(0)
 
48
namespace
 
49
{
 
50
const char* dashses[11] = {
 
51
    "", "Dash_20_2", "Dash_20_3", "Dash_20_2", "Dash_20_2", "Dash_20_2",
 
52
    "Dash_20_4", "Dash_20_6", "Dash_20_5", "Dash_20_7", "Dash_20_8"
 
53
};
 
54
const char* arrowHeads[6] = {
 
55
    "", "msArrowEnd_20_5", "msArrowStealthEnd_20_5", "msArrowDiamondEnd_20_5",
 
56
    "msArrowOvalEnd_20_5", "msArrowOpenEnd_20_5"
 
57
};
 
58
QString format(double v) {
 
59
    static const QString f("%1");
 
60
    static const QString e("");
 
61
    static const QRegExp r("\\.?0+$");
 
62
    return f.arg(v, 0, 'f').replace(r, e);
 
63
}
 
64
QString pt(double v) {
 
65
    static const QString pt("pt");
 
66
    return format(v) + pt;
 
67
}
 
68
QString percent(double v) {
 
69
    return format(v) + '%';
 
70
}
 
71
QString mm(double v) {
 
72
    static const QString mm("mm");
 
73
    return format(v) + mm;
 
74
}
 
75
}
 
76
 
 
77
/*
 
78
 * ************************************************
 
79
 * Drawing Writer
 
80
 * ************************************************
 
81
 */
 
82
DrawingWriter::DrawingWriter(KoXmlWriter& xmlWriter, KoGenStyles& kostyles,
 
83
                             bool stylesxml_, bool inlineObj)
 
84
        : Writer(xmlWriter, kostyles, stylesxml_),
 
85
          xLeft(0),
 
86
          xRight(0),
 
87
          yTop(0),
 
88
          yBottom(0),
 
89
          m_pSpa(0),
 
90
          m_picf(0),
 
91
          m_rgbUid(0),
 
92
          m_bodyDrawing(true),
 
93
          m_inline(inlineObj)
366
94
{
367
95
    scaleX = 25.4 / 1440;
368
96
    scaleY = 25.4 / 1440;
369
97
}
370
98
 
371
 
QString DrawingWriter::vLength()
 
99
qreal DrawingWriter::vLength()
372
100
{
373
101
    return Writer::vLength(yBottom - yTop);
374
102
}
375
103
 
376
 
QString DrawingWriter::hLength()
 
104
qreal DrawingWriter::hLength()
377
105
{
378
106
    return Writer::hLength(xRight - xLeft);
379
107
}
380
108
 
381
 
QString DrawingWriter::vOffset()
 
109
qreal DrawingWriter::vOffset()
382
110
{
383
111
    return Writer::vOffset(yTop);
384
112
}
385
113
 
386
 
QString DrawingWriter::hOffset()
 
114
qreal DrawingWriter::hOffset()
387
115
{
388
116
    return Writer::hOffset(xLeft);
389
117
}
398
126
 
399
127
void DrawingWriter::SetGroupRectangle(MSO::OfficeArtFSPGR& fspgr)
400
128
{
401
 
    if(fspgr.xRight == fspgr.xLeft) {
 
129
    if (fspgr.xRight == fspgr.xLeft) {
402
130
        return;
403
131
    }
404
132
 
405
 
    if(fspgr.yBottom == fspgr.yTop)
 
133
    if (fspgr.yBottom == fspgr.yTop)
406
134
        return;
407
135
 
408
136
    xOffset = xOffset + xLeft*scaleX;
423
151
    yBottom = anchor.yBottom;
424
152
}
425
153
 
426
 
KWordDrawingHandler::KWordDrawingHandler(Document* doc, KoGenStyles* mainStyles, KoXmlWriter* bodyWriter): QObject()
427
 
, m_doc(doc)
 
154
/*
 
155
 * ************************************************
 
156
 * Graphics Handler
 
157
 * ************************************************
 
158
 */
 
159
KWordGraphicsHandler::KWordGraphicsHandler(Document* doc, KoXmlWriter* bodyWriter,
 
160
                                         KoXmlWriter* manifestWriter, KoStore* store,
 
161
                                         KoGenStyles* mainStyles)
 
162
: QObject()
 
163
, m_document(doc)
 
164
, m_store(store)
 
165
, m_bodyWriter(bodyWriter)
 
166
, m_manifestWriter(manifestWriter)
428
167
, m_mainStyles(mainStyles)
429
 
, m_bodyWriter(bodyWriter)
430
168
, m_drawings(0)
 
169
, m_fib(0)
431
170
, m_pOfficeArtHeaderDgContainer(0)
432
171
, m_pOfficeArtBodyDgContainer(0)
 
172
, m_zIndex(0)
433
173
{
434
 
 
 
174
    kDebug(30513) ;
435
175
}
436
176
 
437
 
KWordDrawingHandler::~KWordDrawingHandler()
 
177
KWordGraphicsHandler::~KWordGraphicsHandler()
438
178
{
439
179
    delete m_pOfficeArtHeaderDgContainer;
440
180
    delete m_pOfficeArtBodyDgContainer;
441
181
}
442
182
 
443
 
void KWordDrawingHandler::init(Drawings * pDrawings, wvWare::OLEStreamReader* table,const  wvWare::Word97::FIB &fib)
 
183
/*
 
184
 * NOTE: All containers parsed by this function are optional.
 
185
 */
 
186
void KWordGraphicsHandler::init(Drawings * pDrawings, const wvWare::Word97::FIB &fib)
444
187
{
445
188
    kDebug(30513);
446
189
 
447
 
    parseOfficeArtContainer(table,fib);
448
 
 
449
 
//     create default draw style
450
 
//    KoGenStyle style(KoGenStyle::GraphicStyle, "graphic");
451
 
//    style.setDefaultStyle(true);
452
 
//
453
 
//    defineDefaultGraphicProperties(&style,pDrawings);
454
 
//
455
 
//    //add default draw style to styles
456
 
//    m_mainStyles->insert(style, "");
 
190
    //TODO: do not use POLE storage here, get the pointer to the stream, have
 
191
    //to access FIB first in mswordodfimport.cpp
 
192
    parseOfficeArtContainer(m_document->storage(), fib);
 
193
 
 
194
    //create default GraphicStyle using information from OfficeArtDggContainer
 
195
    defineDefaultGraphicStyle(m_mainStyles);
 
196
 
 
197
    //parse and store floating pictures  
 
198
    parseFloatingPictures();
 
199
    m_picNames = createFloatingPictures(m_store, m_manifestWriter);
457
200
 
458
201
    m_drawings = pDrawings;
459
 
}
460
 
 
461
 
void KWordDrawingHandler::drawingData(unsigned int globalCP)
462
 
{
463
 
    kDebug(30513);
464
 
 
 
202
    m_fib = const_cast<wvWare::Word97::FIB *>(&fib);
 
203
 
 
204
    //Provide the backgroud color information to the Document, if present.
 
205
    DrawStyle ds = getDrawingStyle();
 
206
    if (ds.fFilled()) {
 
207
        MSO::OfficeArtCOLORREF fc = ds.fillColor();
 
208
        QColor color = QColor(fc.red, fc.green, fc.blue);
 
209
        QString tmp = color.name();
 
210
        if (tmp != m_document->currentBgColor()) {
 
211
            m_document->updateBgColor(tmp);
 
212
        }
 
213
    }
 
214
    return;
 
215
}
 
216
 
 
217
void KWordGraphicsHandler::handleInlineObject(const wvWare::PictureData& data)
 
218
{
 
219
    kDebug(30513) ;
 
220
    // going to parse and process the Data stream content
 
221
    LEInputStream* in = m_document->data_stream();
 
222
    int size = (data.picf->lcb - data.picf->cbHeader);
 
223
 
 
224
    kDebug(30513) << "\nCurrent stream position: " << in->getPosition()
 
225
                  << "\nOfficeArtInlineSpContainer offset: " << data.fcPic
 
226
                  << "\nPICF size: " << data.picf->cbHeader
 
227
                  << "\nOfficeArtData size: " << size;
 
228
 
 
229
    // parse the OfficeArtInlineSpContainer and rewind the stream
 
230
    LEInputStream::Mark _zero;
 
231
    _zero = in->setMark();
 
232
    in->skip(data.fcPic);
 
233
    OfficeArtInlineSpContainer co;
 
234
    parseOfficeArtInlineSpContainer(*in, co);
 
235
 
 
236
    int n = (data.fcPic + size) - in->getPosition();
 
237
    if (n) {
 
238
        kDebug(30513) << "Warning: " << n
 
239
                      << " bytes left while parsing OfficeArtInlineSpContainer";
 
240
    }
 
241
    in->rewind(_zero);
 
242
 
 
243
    // store picture data if present and update m_picNames
 
244
    PictureReference ref;
 
245
    m_store->enterDirectory("Pictures");
 
246
    foreach (const OfficeArtBStoreContainerFileBlock& block, co.rgfb) {
 
247
        const OfficeArtFBSE* fbse = block.anon.get<MSO::OfficeArtFBSE>();
 
248
        if (!fbse) {
 
249
            kDebug(30513) << "Warning: FBSE container not found, skipping ";
 
250
        }
 
251
        else {
 
252
            //check if this BLIP is already in hash table
 
253
            if (m_picNames.contains(fbse->rgbUid)) {
 
254
                ref.uid = fbse->rgbUid;
 
255
                continue;
 
256
            }
 
257
            else {
 
258
                ref = savePicture(block, m_store);
 
259
                if (ref.name.length() == 0) {
 
260
                    kDebug(30513) << "empty name in picture reference";
 
261
                    break;
 
262
                }
 
263
                m_manifestWriter->addManifestEntry("Pictures/" + ref.name, ref.mimetype);
 
264
                m_picNames[ref.uid] = ref.name;
 
265
            }
 
266
        }
 
267
    }
 
268
    m_store->leaveDirectory();
 
269
 
 
270
    DrawingWriter out(*m_bodyWriter, *m_mainStyles, true, true);
 
271
    out.m_picf = data.picf;
 
272
    out.m_rgbUid = ref.uid;
 
273
 
 
274
    OfficeArtSpContainer* o = &(co.shape);
 
275
    processDrawingObject(*o, out);
 
276
}
 
277
 
 
278
void KWordGraphicsHandler::handleFloatingObject(unsigned int globalCP)
 
279
{
 
280
    kDebug(30513) << "globalCP" << globalCP ;
465
281
    // draw shape or group of shapes
466
 
    if(m_drawings == NULL) {
 
282
    if (m_drawings == NULL) {
467
283
        return;
468
284
    }
469
285
 
470
286
    PLCF<Word97::FSPA>* fspa = m_drawings->getSpaMom();
471
 
    if(fspa == NULL) {
472
 
        return;
 
287
    if (fspa != 0) {
 
288
        PLCFIterator<Word97::FSPA> it(fspa->at(0));
 
289
 
 
290
        //search for drawing in main body
 
291
        for (size_t i = 0; i < fspa->count(); i++, ++it) {
 
292
            kDebug(30513) << "FSPA start:" << it.currentStart();
 
293
            kDebug(30513) << "FSPA spid:" << it.current()->spid;
 
294
 
 
295
            if (it.currentStart() == globalCP) {
 
296
                DrawingWriter out(*m_bodyWriter, *m_mainStyles, true, false);
 
297
                out.m_pSpa = it.current();
 
298
                out.m_bodyDrawing = true;
 
299
                locateDrawing((m_pOfficeArtBodyDgContainer->groupShape).data(), out,
 
300
                              it.current(), (uint) it.current()->spid);
 
301
                return;
 
302
            }
 
303
        }
473
304
    }
474
305
 
475
 
    PLCFIterator<Word97::FSPA> it( fspa->at( 0 ) );
476
 
 
477
 
    kDebug(30513) << "globalCP" << globalCP ;
478
 
 
479
 
    //search for drawing
480
 
    for(size_t i = 0; i < fspa->count(); i++, ++it) {
481
 
        kDebug(30513) << "FSPA start:" << it.currentStart();
482
 
        kDebug(30513) << "FSPA spid:" << it.current()->spid;
483
 
 
484
 
        if(it.currentStart() == globalCP) {
485
 
            KoGenStyles tmpStyles; //not used yet
486
 
            DrawingWriter out(*m_bodyWriter,tmpStyles,true);
487
 
            drawObject((uint) it.current()->spid, m_pOfficeArtBodyDgContainer, out,it.current());
488
 
            break;
 
306
    fspa = m_drawings->getSpaHdr();
 
307
    if (fspa != 0) {
 
308
        PLCFIterator<Word97::FSPA> itHeader(fspa->at(0));
 
309
        //search for drawing in header
 
310
        for (size_t i = 0; i < fspa->count(); i++, ++itHeader) {
 
311
            kDebug(30513) << "FSPA start:" << itHeader.currentStart() + m_fib->ccpText + m_fib->ccpFtn;
 
312
            kDebug(30513) << "FSPA spid:" << itHeader.current()->spid;
 
313
 
 
314
            if ((itHeader.currentStart() + m_fib->ccpText + m_fib->ccpFtn)  == globalCP) {
 
315
                DrawingWriter out(*m_bodyWriter, *m_mainStyles, true, false);
 
316
                out.m_pSpa = itHeader.current();
 
317
                out.m_bodyDrawing = false;
 
318
                locateDrawing((m_pOfficeArtHeaderDgContainer->groupShape).data(), out,
 
319
                              itHeader.current(), (uint) itHeader.current()->spid);
 
320
                return;
 
321
            }
489
322
        }
490
323
    }
491
324
}
492
325
 
493
 
void KWordDrawingHandler::setBodyWriter(KoXmlWriter* writer)
 
326
void KWordGraphicsHandler::setBodyWriter(KoXmlWriter* writer)
494
327
{
495
328
    m_bodyWriter = writer;
496
329
}
497
330
 
498
 
DrawStyle KWordDrawingHandler::getDrawingStyle()
 
331
DrawStyle KWordGraphicsHandler::getDrawingStyle()
499
332
{
500
 
    if(m_pOfficeArtBodyDgContainer != NULL) {
501
 
        if(m_pOfficeArtBodyDgContainer->shape.isNull() == false) {
502
 
            if((*m_pOfficeArtBodyDgContainer->shape).shapePrimaryOptions.isNull() == false ) {
503
 
                return DrawStyle(m_OfficeArtDggContainer,NULL,m_pOfficeArtBodyDgContainer->shape.data());
504
 
                }
 
333
    if (m_pOfficeArtBodyDgContainer != NULL) {
 
334
        if (m_pOfficeArtBodyDgContainer->shape.isNull() == false) {
 
335
            if ((*m_pOfficeArtBodyDgContainer->shape).shapePrimaryOptions.isNull() == false) {
 
336
                return DrawStyle(m_OfficeArtDggContainer, NULL, m_pOfficeArtBodyDgContainer->shape.data());
505
337
            }
506
338
        }
 
339
    }
507
340
    return DrawStyle(m_OfficeArtDggContainer);
508
341
}
509
342
 
510
 
void KWordDrawingHandler::drawObject(uint spid, MSO::OfficeArtDgContainer * dg, DrawingWriter& out
511
 
        , wvWare::Word97::FSPA* spa)
 
343
void KWordGraphicsHandler::locateDrawing(const MSO::OfficeArtSpgrContainer* spgr, DrawingWriter& out, 
 
344
                                         wvWare::Word97::FSPA* spa, uint spid)
512
345
{
513
 
    if(dg == NULL)
 
346
    if (spgr == NULL) {
514
347
        return;
515
 
 
516
 
    foreach(const OfficeArtSpgrContainerFileBlock& co, dg->groupShape.rgfb) {
517
 
        //if spgr is in root, find out if his first item is sp with right spid
 
348
    }
 
349
    m_zIndex = 0;
 
350
 
 
351
    //FIXME: combine childAnchor, shapeGroup coordinates with information from
 
352
    //clientAnchor pointing to the SPA structure!
 
353
 
 
354
    //NOTE: The OfficeArtSpgrContainer record specifies a container for groups
 
355
    //(4) of shapes.  The group (4) container contains a variable number of
 
356
    //shape containers and other group (4) containers.  Each group (4) is a
 
357
    //shape.  The first container MUST be an OfficeArtSpContainer record, which
 
358
    //MUST contain shape information for the group. MS-ODRAW, 2.2.16
 
359
 
 
360
    foreach (const OfficeArtSpgrContainerFileBlock& co, spgr->rgfb) {
 
361
 
518
362
        if (co.anon.is<OfficeArtSpgrContainer>()) {
519
 
            const OfficeArtSpContainer* first =
520
 
                    (*co.anon.get<OfficeArtSpgrContainer>()).rgfb[0].anon.get<OfficeArtSpContainer>();
521
 
 
522
 
            if(first && first->shapeProp.spid == spid) {
523
 
                out.SetRectangle(*spa);
524
 
                processObjectForBody(*co.anon.get<OfficeArtSpgrContainer>(), out); //draw group
525
 
                break;
526
 
            }
527
 
        }
528
 
        else //if sp is in root, find out if it has the right spid
529
 
        {
530
 
            const OfficeArtSpContainer & spCo = *co.anon.get<OfficeArtSpContainer>();
531
 
 
532
 
            if(spCo.shapeProp.spid == spid) {
533
 
                out.SetRectangle(*spa);
534
 
                processObjectForBody(spCo, out); //draw object
535
 
                break;
536
 
            }
 
363
            const OfficeArtSpContainer* first = 
 
364
                (*co.anon.get<OfficeArtSpgrContainer>()).rgfb[0].anon.get<OfficeArtSpContainer>();
 
365
            if (first && first->shapeProp.spid == spid) {
 
366
                out.SetRectangle(*spa);
 
367
                processGroup(*co.anon.get<OfficeArtSpgrContainer>(), out);
 
368
                break;
 
369
            } else {
 
370
                m_zIndex = m_zIndex + (*co.anon.get<OfficeArtSpgrContainer>()).rgfb.size();
 
371
            }
 
372
        } else {
 
373
            const OfficeArtSpContainer &sp = *co.anon.get<OfficeArtSpContainer>();
 
374
            if (sp.shapeProp.fGroup) {
 
375
                if (sp.shapeGroup) {
 
376
                    out.SetGroupRectangle(*sp.shapeGroup);
 
377
                }
 
378
                if (sp.shapeProp.spid == spid) {
 
379
                    kDebug(30513) << "An unprocessed shape storing information for the group is referred from text!";
 
380
                }
 
381
            } else if (sp.shapeProp.spid == spid) {
 
382
                out.SetRectangle(*spa);
 
383
                processDrawingObject(sp, out);
 
384
                break;
 
385
            }
 
386
            m_zIndex++;
537
387
        }
538
388
    }
539
389
}
540
390
 
541
 
void KWordDrawingHandler::processObjectForBody(const MSO::OfficeArtSpgrContainer& o, DrawingWriter& out)
 
391
void KWordGraphicsHandler::processGroup(const MSO::OfficeArtSpgrContainer& o, DrawingWriter& out)
542
392
{
543
 
    if (o.rgfb.size() < 2) return;
544
 
 
 
393
    if (o.rgfb.size() < 2) {
 
394
        return;
 
395
    }
 
396
    //TODO: create corresponding style and apply style properties
545
397
    out.xml.startElement("draw:g");
546
 
 
547
398
    const OfficeArtSpContainer *first = o.rgfb[0].anon.get<OfficeArtSpContainer>();
548
 
    if(first && first->shapeGroup) {
549
 
        out.SetGroupRectangle(*first->shapeGroup); //set group rectangle
 
399
 
 
400
    if (first && first->shapeGroup) {
 
401
        //process shape information for the group
 
402
        out.SetGroupRectangle(*first->shapeGroup);
550
403
    }
551
404
 
552
405
    for (int i = 1; i < o.rgfb.size(); ++i) {
553
 
        if(o.rgfb[i].anon.is<OfficeArtSpContainer>()) {
554
 
 
555
 
            OfficeArtSpContainer tempSp = *o.rgfb[i].anon.get<OfficeArtSpContainer>();
556
 
 
557
 
            if(tempSp.childAnchor) {
558
 
                out.SetClientRectangle(*tempSp.childAnchor); //set child rectangle
 
406
        if (o.rgfb[i].anon.is<OfficeArtSpContainer>()) {
 
407
            OfficeArtSpContainer sp = *o.rgfb[i].anon.get<OfficeArtSpContainer>();
 
408
            if (sp.childAnchor) {
 
409
                out.SetClientRectangle(*sp.childAnchor); //set child rectangle
559
410
            }
560
 
 
561
 
            processObjectForBody(tempSp, out); //draw objects
562
 
        }
 
411
            processDrawingObject(sp, out); //draw objects
 
412
        } 
 
413
        //TODO: another group shape can be here! We should call locateDrawing
 
414
        //again!
563
415
    }
564
 
 
565
416
    out.xml.endElement(); // draw:g
566
417
}
567
418
 
568
 
void KWordDrawingHandler::processObjectForBody(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
 
419
void KWordGraphicsHandler::processDrawingObject(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
569
420
{
570
421
    kDebug(30513);
571
422
 
 
423
    DrawStyle ds(NULL, &o);
 
424
 
 
425
    // check the shape type and process it
 
426
    kDebug(30513) << "shapeType: " << hex << o.shapeProp.rh.recInstance;
 
427
    kDebug(30513) << "grupShape: " << o.shapeProp.fGroup;
 
428
    kDebug(30513) << "Selected properties: ";
 
429
    kDebug(30513) << "pib: " << ds.pib();
 
430
 
572
431
    // textbox can be msosptTextBox or msosptRectangle or ...
573
 
    if(!o.clientTextbox.isNull()) {
 
432
    if (!o.clientTextbox.isNull()) {
574
433
        kDebug(30513)<< "processing text box";
575
434
        parseTextBox(o, out);
576
435
        return;
577
436
    }
578
437
 
579
 
 
580
438
    switch (o.shapeProp.rh.recInstance)
581
439
    {
 
440
        case msosptRectangle: {
 
441
            kDebug(30513)<< "processing rectangle";
 
442
            //check group shape boolean properties for details
 
443
            if (ds.fHorizRule()) {
 
444
                kDebug(30513)<< "processing a line shape";
 
445
                processLineShape(o, out);
 
446
            }
 
447
            processRectangle(o, out);
 
448
            break;
 
449
        }
 
450
        case msosptEllipse:
 
451
            kDebug(30513)<< "processing ellipse";
 
452
            break;
582
453
        case msosptPictureFrame:
583
 
            kDebug(30513)<< "processing picture frame";
584
 
            processPictureFrame(o, out);
 
454
            kDebug(30513)<< "processing a frame shape";
 
455
            if (out.m_inline) {
 
456
                processInlinePictureFrame(o, out);
 
457
            }
 
458
            else {
 
459
                processFloatingPictureFrame(o, out);
 
460
            }
585
461
            break;
586
462
        case msosptHostControl:
587
463
            kDebug(30513)<< "processing host control";
590
466
    }
591
467
}
592
468
 
593
 
void KWordDrawingHandler::parseOfficeArtContainer(wvWare::OLEStreamReader* table,
594
 
        const  wvWare::Word97::FIB &fib)
 
469
void KWordGraphicsHandler::parseOfficeArtContainer(POLE::Storage* storage, const  wvWare::Word97::FIB &fib)
595
470
{
596
471
    kDebug(30513);
597
472
    // get OfficeArtContent
598
 
    if(fib.lcbDggInfo != 0) {
 
473
    if (fib.lcbDggInfo != 0) {
 
474
 
 
475
        const std::string table = fib.fWhichTblStm ? "1Table" : "0Table";
 
476
        POLE::Stream stream(storage, table);
 
477
        QByteArray array;
599
478
        QBuffer buffer;
600
 
        QByteArray array;
601
479
 
602
 
        // copy of OfficeArtContent data into temp buffer
603
480
        array.resize(fib.lcbDggInfo);
604
 
        table->seek( fib.fcDggInfo );
605
 
        table->read( (U8 *)array.data(), fib.lcbDggInfo );
 
481
        stream.seek(fib.fcDggInfo);
 
482
        unsigned long n = stream.read((unsigned char*) array.data(), fib.lcbDggInfo);
 
483
        if (n != fib.lcbDggInfo) {
 
484
            kDebug(30513) << "Failed to read data from " << table.data() << "stream";
 
485
            return;
 
486
        }
606
487
 
607
488
        buffer.setData(array);
608
489
        buffer.open(QIODevice::ReadOnly);
609
 
 
610
 
        // creation of streem needed by simpleParser.h
611
 
        LEInputStream stream(&buffer);
 
490
        LEInputStream in(&buffer);
612
491
 
613
492
        //parse OfficeArfDggContainer from msdoc
614
493
        try {
615
 
            parseOfficeArtDggContainer(stream, m_OfficeArtDggContainer);
 
494
            parseOfficeArtDggContainer(in, m_OfficeArtDggContainer);
616
495
        }
617
496
        catch (IOException e) {
618
 
            kDebug(30513) << "caught IOException while parsing parseOfficeArtDggContainer ";
 
497
            kDebug(30513) << "caught IOException while parsing parseOfficeArtDggContainer";
619
498
            return;
620
499
        }
621
500
        catch (...) {
622
501
            kDebug(30513) << "caught unknown exception while parsing parseOfficeArtDggContainer";
623
502
            return;
624
503
        }
625
 
        kDebug(30513) << "OfficeArtDggContainer parsed successful " ;
626
 
 
 
504
        kDebug(30513) << "OfficeArtDggContainer parsed successfully" ;
627
505
 
628
506
        // parse drawingsVariable from msdoc
629
507
        // 0 - next OfficeArtDgContainer belongs to Main document;
630
508
        // 1 - next OfficeArtDgContainer belongs to Header Document
631
509
        unsigned char drawingsVariable = 0;
632
510
        try {
633
 
            drawingsVariable = stream.readuint8();
 
511
            drawingsVariable = in.readuint8();
634
512
        }
635
513
        catch (IOException e) {
636
514
            kDebug(30513) << "caught IOException while parsing drawingsVariable ";
642
520
        }
643
521
 
644
522
        //parse OfficeArfDgContainer from msdoc
645
 
        OfficeArtDgContainer * pDgContainer = NULL;
 
523
        OfficeArtDgContainer *pDgContainer = NULL;
646
524
        try {
647
525
            pDgContainer = new OfficeArtDgContainer();
648
 
            if(drawingsVariable == 0) {
 
526
            if (drawingsVariable == 0) {
649
527
                m_pOfficeArtBodyDgContainer = pDgContainer;
650
528
            } else {
651
529
                m_pOfficeArtHeaderDgContainer = pDgContainer;
652
530
            }
653
 
            parseOfficeArtDgContainer(stream, *pDgContainer);
 
531
            parseOfficeArtDgContainer(in, *pDgContainer);
654
532
        }
655
533
        catch (IOException e) {
656
534
            kDebug(30513) << "caught IOException while parsing OfficeArtDgContainer ";
665
543
        // 0 - next OfficeArtDgContainer belongs to Main document;
666
544
        // 1 - next OfficeArtDgContainer belongs to Header Document
667
545
        try {
668
 
            drawingsVariable = stream.readuint8();
 
546
            drawingsVariable = in.readuint8();
669
547
        }
670
548
        catch (IOException e) {
671
549
            kDebug(30513) << "caught IOException while parsing second drawingsVariable ";
672
 
            //wvlog << "stream position: " << stream.getPosition() << std::endl;
 
550
            //wvlog << "in position: " << in.getPosition() << std::endl;
673
551
            return;
674
552
        }
675
553
        catch (...) {
681
559
        pDgContainer = NULL;
682
560
        try {
683
561
            pDgContainer = new OfficeArtDgContainer();
684
 
            if(drawingsVariable == 0) {
685
 
                if(m_pOfficeArtBodyDgContainer!= NULL){
 
562
            if (drawingsVariable == 0) {
 
563
                if (m_pOfficeArtBodyDgContainer != NULL){
686
564
                    delete m_pOfficeArtBodyDgContainer;
687
565
                }
688
566
                m_pOfficeArtBodyDgContainer = pDgContainer;
689
567
            }
690
 
            else
691
 
            {
692
 
                if(m_pOfficeArtHeaderDgContainer != NULL) {
 
568
            else {
 
569
                if (m_pOfficeArtHeaderDgContainer != NULL) {
693
570
                    delete m_pOfficeArtHeaderDgContainer;
694
571
                }
695
572
                m_pOfficeArtHeaderDgContainer = pDgContainer;
696
573
            }
697
 
            parseOfficeArtDgContainer(stream, *pDgContainer);
 
574
            parseOfficeArtDgContainer(in, *pDgContainer);
698
575
        }
699
576
        catch (IOException e) {
700
577
            kDebug(30513) << "caught IOException while parsing second OfficeArtDgContainer ";
705
582
            return;
706
583
        }
707
584
 
708
 
        if (stream.getPosition() != buffer.size()) {
709
 
            kDebug(30513) << (uint)(buffer.size() - stream.getPosition())
 
585
        if (in.getPosition() != buffer.size()) {
 
586
            kDebug(30513) << (uint)(buffer.size() - in.getPosition())
710
587
            << "bytes left at the end of parseOfficeArtDggContainer,"
711
588
            << " parseOfficeArtDgContainer, so probably an error at position "
712
 
            << (uint)stream.getMaxPosition();
713
 
        }
714
 
    }
715
 
}
716
 
 
717
 
void KWordDrawingHandler::parseTextBox(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
718
 
{
719
 
    out.xml.startElement("draw:frame");
720
 
 
 
589
            << (uint) in.getMaxPosition();
 
590
        }
 
591
    }
 
592
    return;
 
593
}
 
594
 
 
595
void KWordGraphicsHandler::defineDefaultGraphicStyle(KoGenStyles* styles)
 
596
{
 
597
    // write style <style:default-style style:family="graphic">
 
598
    KoGenStyle style(KoGenStyle::GraphicStyle, "graphic");
 
599
    DrawStyle ds(m_OfficeArtDggContainer);
 
600
    style.setDefaultStyle(true);
 
601
    defineGraphicProperties(style, ds);
 
602
    styles->insert(style);
 
603
}
 
604
 
 
605
void KWordGraphicsHandler::defineGraphicProperties(KoGenStyle& style, const DrawStyle& ds,
 
606
                                                  const QString& listStyle)
 
607
{
 
608
    MSO::OfficeArtCOLORREF clr;
 
609
    const KoGenStyle::PropertyType gt = KoGenStyle::GraphicType;
 
610
    // dr3d:ambient-color
 
611
    // dr3d:back-scale
 
612
    // dr3d:backface-culling
 
613
    // dr3d:close-back
 
614
    // dr3d:close-front
 
615
    // dr3d:depth
 
616
    // dr3d:diffuse-color
 
617
    // dr3d:edge-rounding
 
618
    // dr3d:edge-rounding-mode
 
619
    // dr3d:emissive-color
 
620
    // dr3d:end-angle
 
621
    // dr3d:horizontal-segments
 
622
    // dr3d:lighting-mode
 
623
    // dr3d:normals-direction
 
624
    // dr3d:normals-kind
 
625
    // dr3d:shadow
 
626
    // dr3d:shininess
 
627
    // dr3d:specular-color
 
628
    // dr3d:texture-filter
 
629
    // dr3d:texture-generation-mode-x
 
630
    // dr3d:texture-generation-mode-y
 
631
    // dr3d:texture-kind
 
632
    // dr3d:texture-mode
 
633
    // dr3d:vertical-segments
 
634
    // draw:auto-grow-height
 
635
    // draw:auto-grow-width
 
636
    // draw:blue
 
637
    // draw:caption-angle
 
638
    // draw:caption-angle-type
 
639
    // draw:caption-escape
 
640
    // draw:caption-escape-direction
 
641
    // draw:caption-fit-line-length
 
642
    // draw:caption-gap
 
643
    // draw:caption-line-length
 
644
    // draw:caption-type
 
645
    // draw:color-inversion
 
646
    // draw:color-mode
 
647
    // draw:contrast
 
648
    // draw:decimal-places
 
649
    // draw:end-guide
 
650
    // draw:end-line-spacing-horizontal
 
651
    // draw:end-line-spacing-vertical
 
652
 
 
653
    // NOTE: fFilled specifies whether fill of the shape is render based on the
 
654
    // properties of the "fill style" property set.
 
655
    if (ds.fFilled()) {
 
656
        qint32 fillType = ds.fillType();
 
657
        // draw:fill ("bitmap", "gradient", "hatch", "none" or "solid")
 
658
        style.addProperty("draw:fill", getFillType(fillType), gt);
 
659
        // NOTE: only set the color if the fill type is 'solid' because OOo
 
660
        // ignores fill='none' if the color is set
 
661
        if (fillType == 0) {
 
662
            clr = ds.fillColor();
 
663
            style.addProperty("draw:fill-color", QColor(clr.red, clr.green, clr.blue).name(), gt);
 
664
        }
 
665
    } else {
 
666
        style.addProperty("draw:fill", "none", gt);
 
667
    }
 
668
    // draw:fill-gradient-name
 
669
    // draw:fill-hatch-name
 
670
    // draw:fill-hatch-solid
 
671
    // draw:fill-image-name
 
672
    // draw:fill-image-ref-point
 
673
    // draw:fill-image-ref-point-x
 
674
    // draw:fill-image-ref-point-y
 
675
    // draw:fill-image-height
 
676
    // draw:fill-image-width
 
677
    // draw:fit-to-contour
 
678
    // draw:fit-to-size
 
679
    // draw:frame-display-border
 
680
    // draw:frame-display-scrollbar
 
681
    // draw:frame-margin-horizontal
 
682
    // draw:frame-margin-vertical
 
683
    // draw:gamma
 
684
    // draw:gradient-step-count
 
685
    // draw:green
 
686
    // draw:guide-distance
 
687
    // draw:guide-overhang
 
688
    // draw:image-opacity
 
689
    // draw:line-distance
 
690
    // draw:luminance
 
691
    // draw:marker-end
 
692
    quint32 lineEndArrowhead = ds.lineEndArrowhead();
 
693
    if (lineEndArrowhead > 0 && lineEndArrowhead < 6) {
 
694
        style.addProperty("draw:marker-end", arrowHeads[lineEndArrowhead], gt);
 
695
    }
 
696
    // draw:marker-end-center
 
697
    // draw:marker-end-width
 
698
    qreal lineWidthPt = ds.lineWidth() / 12700.;
 
699
    style.addProperty("draw:marker-end-width",
 
700
                      pt(lineWidthPt*4*(1+ds.lineEndArrowWidth())), gt);
 
701
    // draw:marker-start
 
702
    quint32 lineStartArrowhead = ds.lineStartArrowhead();
 
703
    if (lineStartArrowhead > 0 && lineStartArrowhead < 6) {
 
704
        style.addProperty("draw:marker-start", arrowHeads[lineStartArrowhead],
 
705
                          gt);
 
706
    }
 
707
    // draw:marker-start-center
 
708
    // draw:marker-start-width
 
709
    style.addProperty("draw:marker-start-width",
 
710
                      pt(lineWidthPt*4*(1+ds.lineStartArrowWidth())), gt);
 
711
    // draw:measure-align
 
712
    // draw:measure-vertical-align
 
713
    // draw:ole-draw-aspect
 
714
    // draw:opacity
 
715
    // draw:opacity-name
 
716
    // draw:parallel
 
717
    // draw:placing
 
718
    // draw:red
 
719
    // draw:secondary-fill-color
 
720
 
 
721
    // NOTE: fShadow property specifies whether the shape has a shadow.
 
722
    if (ds.fShadow()) {
 
723
        // draw:shadow
 
724
        style.addProperty("draw:shadow", "visible", gt);
 
725
        // draw:shadow-color
 
726
        clr = ds.shadowColor();
 
727
        style.addProperty("draw:shadow-color", QColor(clr.red, clr.green, clr.blue).name(), gt);
 
728
        //shadowOffset* properties MUST exist if shadowType property equals
 
729
        //msoshadowOffset or msoshadowDouble, otherwise MUST be ignored,
 
730
        //MS-ODRAW 2.3.13.6
 
731
        quint32 type = ds.shadowType();
 
732
        if ((type == 0) || (type == 1)) {
 
733
            // draw:shadow-offset-x
 
734
            style.addProperty("draw:shadow-offset-x", pt(ds.shadowOffsetX()/12700.), gt);
 
735
            // draw:shadow-offset-y
 
736
            style.addProperty("draw:shadow-offset-y", pt(ds.shadowOffsetY()/12700.), gt);
 
737
        }
 
738
        // draw:shadow-opacity
 
739
        float shadowOpacity = toQReal(ds.shadowOpacity());
 
740
        style.addProperty("draw:shadow-opacity", percent(100*shadowOpacity), gt);
 
741
    } else {
 
742
        style.addProperty("draw:shadow", "hidden");
 
743
    }
 
744
    // draw:show-unit
 
745
    // draw:start-guide
 
746
    // draw:start-line-spacing-horizontal
 
747
    // draw:start-line-spacing-vertical
 
748
    // draw:stroke ('dash', 'none' or 'solid')
 
749
    quint32 lineDashing = ds.lineDashing();
 
750
    // OOo interprets solid line with with 0 as hairline, so if
 
751
    // width == 0, stroke *must* be none to avoid OOo from
 
752
    // displaying a line
 
753
    if (lineWidthPt == 0) {
 
754
        style.addProperty("draw:stroke", "none", gt);
 
755
    } else if (ds.fLine() || ds.fNoLineDrawDash()) {
 
756
        if (lineDashing > 0 && lineDashing < 11) {
 
757
            style.addProperty("draw:stroke", "dash", gt);
 
758
        } else {
 
759
            style.addProperty("draw:stroke", "solid", gt);
 
760
        }
 
761
    } else {
 
762
        style.addProperty("draw:stroke", "none", gt);
 
763
    }
 
764
    // draw:stroke-dash from 2.3.8.17 lineDashing
 
765
    if (lineDashing > 0 && lineDashing < 11) {
 
766
        style.addProperty("draw:stroke-dash", dashses[lineDashing], gt);
 
767
    }
 
768
    // draw:stroke-dash-names
 
769
    // draw:stroke-linejoin
 
770
    // draw:symbol-color
 
771
    // draw:textarea-horizontal-align
 
772
    // draw:textarea-vertical-align
 
773
    // draw:tile-repeat-offset
 
774
    // draw:unit
 
775
    // draw:visible-area-height
 
776
    // draw:visible-area-left
 
777
    // draw:visible-area-top
 
778
    // draw:visible-area-width
 
779
    // draw:wrap-influence-on-position
 
780
    // fo:background-color
 
781
    // fo:border
 
782
    // fo:border-bottom
 
783
    // fo:border-left
 
784
    // fo:border-right
 
785
    // fo:border-top
 
786
    // fo:clip
 
787
    // fo:max-height
 
788
    // fo:max-width
 
789
    // fo:min-height
 
790
    // fo:min-width
 
791
    // fo:padding
 
792
    // fo:padding-left
 
793
    // fo:padding-top
 
794
    // fo:padding-right
 
795
    // fo:padding-bottom
 
796
    // fo:wrap-option
 
797
    // style:border-line-width
 
798
    // style:border-line-width-bottom
 
799
    // style:border-line-width-left
 
800
    // style:border-line-width-right
 
801
    // style:border-line-width-top
 
802
    // style:editable
 
803
    // style:flow-with-text
 
804
    // style:mirror
 
805
    // style:overflow-behavior
 
806
    // style:print-content
 
807
    // style:protect
 
808
    // style:rel-height
 
809
    // style:rel-width
 
810
    // style:repeat
 
811
    // svg:fill-rule
 
812
    // svg:height
 
813
    // svg:stroke-color from 2.3.8.1 lineColor
 
814
    clr = ds.lineColor();
 
815
    QColor lineColor(clr.red,clr.green,clr.blue);
 
816
    style.addProperty("svg:stroke-color", lineColor.name(), gt);
 
817
    // svg:stroke-opacity from 2.3.8.2 lineOpacity
 
818
    style.addProperty("svg:stroke-opacity",
 
819
                      percent(100.0 * ds.lineOpacity() / 0x10000), gt);
 
820
    // svg:stroke-width from 2.3.8.14 lineWidth
 
821
    style.addProperty("svg:stroke-width", pt(lineWidthPt), gt);
 
822
    // svg:width
 
823
    // svg:x
 
824
    // svg:y
 
825
    // text:anchor-page-number
 
826
    // text:anchor-type
 
827
    // text:animation
 
828
    // text:animation-delay
 
829
    // text:animation-direction
 
830
    // text:animation-repeat
 
831
    // text:animation-start-inside
 
832
    // text:animation-steps
 
833
    // text:animation-stop-inside
 
834
 
 
835
    /* associate with a text:list-style element */
 
836
    if (!listStyle.isNull()) {
 
837
        style.addAttribute("style:list-style-name", listStyle);
 
838
    }
 
839
}
 
840
 
 
841
void KWordGraphicsHandler::defineAnchorProperties(KoGenStyle& style, const DrawStyle& ds)
 
842
{
 
843
    // style:horizontal-pos MS-ODRAW - 2.3.4.19
 
844
    quint32 posH = ds.posH();
 
845
    if (posH == 0) {  // msophAbs
 
846
        style.addProperty("style:horizontal-pos","from-left");
 
847
    } else if (posH == 1) { // msophLeft
 
848
        style.addProperty("style:horizontal-pos","left");
 
849
    } else if (posH == 2) { // msophCenter
 
850
        style.addProperty("style:horizontal-pos","center");
 
851
    } else if (posH == 3) { // msophRight
 
852
        style.addProperty("style:horizontal-pos","right");
 
853
    } else if (posH == 4) { // msophInside
 
854
        style.addProperty("style:horizontal-pos","inside");
 
855
    } else if (posH == 5) { // msophOutside
 
856
        style.addProperty("style:horizontal-pos","outside");
 
857
    }
 
858
 
 
859
    // style:horizontal-rel MS-ODRAW 2.3.4.20
 
860
    quint32 posRelH = ds.posRelH();
 
861
 
 
862
    if (posRelH == 0) {//msoprhMargin
 
863
        style.addProperty("style:horizontal-rel","page-content");
 
864
    } else if (posRelH == 1) {//msoprhPage
 
865
        style.addProperty("style:horizontal-rel","page");
 
866
    } else if (posRelH == 2) {//msoprhText
 
867
        style.addProperty("style:horizontal-rel","paragraph");
 
868
    } else if (posRelH == 3) {//msoprhChar
 
869
        style.addProperty("style:horizontal-rel","char");
 
870
    } else {
 
871
        style.addProperty("style:horizontal-rel","page-content");
 
872
    }
 
873
 
 
874
    // style:vertical-pos MS-ODRAW - 2.3.4.21
 
875
    quint32 posV = ds.posV();
 
876
    if (posV == 0) {  // msophAbs
 
877
        style.addProperty("style:vertical-pos","from-top");
 
878
    } else if (posV == 1) { // msophTop
 
879
        style.addProperty("style:vertical-pos","top");
 
880
    } else if (posV == 2) { // msophCenter
 
881
        style.addProperty("style:vertical-pos","middle");
 
882
    } else if (posV == 3) { // msophBottom
 
883
        style.addProperty("style:vertical-pos","bottom");
 
884
    } else if (posV == 4) { // msophInside - not possible to write it into odf
 
885
        style.addProperty("style:vertical-pos","top");
 
886
    } else if (posV == 5) { // msophOutside - not possible to write it into odf
 
887
        style.addProperty("style:vertical-pos","bottom");
 
888
    }
 
889
 
 
890
    // style:vertical-rel MS-ODRAW 2.3.4.22
 
891
    quint32 posRelV = ds.posRelV();
 
892
    if (posRelV == 0) {//msoprvMargin
 
893
        style.addProperty("style:vertical-rel","page-content");
 
894
    } else if (posRelV == 1) {//msoprvPage
 
895
        style.addProperty("style:vertical-rel","page");
 
896
    } else if (posRelV == 2) {//msoprvText
 
897
        style.addProperty("style:vertical-rel","paragraph");
 
898
    } else if (posRelV == 3) { //msoprvLine
 
899
        style.addProperty("style:vertical-rel","line");
 
900
    } else {
 
901
        style.addProperty("style:vertical-rel","page-content");
 
902
    }
 
903
}
 
904
 
 
905
void KWordGraphicsHandler::defineWrappingProperties(KoGenStyle& style, const DrawStyle& ds, const wvWare::Word97::FSPA* spa)
 
906
{
 
907
    //process the wrapping style, (MS-DOC, page 464)
 
908
    if (spa != 0) {
 
909
        bool check_wrk = false;
 
910
        if (spa->wr == 0) {
 
911
            //wrap around the object
 
912
            check_wrk = true;
 
913
        }
 
914
        else if (spa->wr == 1) {
 
915
            //top and bottom wrapping
 
916
            style.addProperty("style:wrap", "none");
 
917
        }
 
918
        else if (spa->wr == 2) {
 
919
            //square wrapping
 
920
            check_wrk = true;
 
921
        }
 
922
        else if (spa->wr == 3) {
 
923
            //in front or behind the text
 
924
            style.addProperty("style:wrap", "run-through");
 
925
            //check if shape is behind the text
 
926
            if ((spa->fBelowText == 1) || (ds.fBehindDocument())) {
 
927
                style.addProperty("style:run-through", "background");
 
928
            } else {
 
929
                style.addProperty("style:run-through", "foreground");
 
930
            }
 
931
        }
 
932
        else if (spa->wr == 4) {
 
933
            //tight wrapping
 
934
            check_wrk = true;
 
935
            style.addProperty("style:wrap-contour", "true");
 
936
            style.addProperty("style:wrap-contour-mode", "outside");
 
937
        }
 
938
        else if (spa->wr == 5) {
 
939
            //through wrapping
 
940
            check_wrk = true;
 
941
            style.addProperty("style:wrap-contour", "true");
 
942
            style.addProperty("style:wrap-contour-mode", "full");
 
943
        }
 
944
        //check details of the text wrapping around this shape
 
945
        if (check_wrk) {
 
946
            if (spa->wrk == 0) {
 
947
                style.addProperty("style:wrap", "parallel");
 
948
            }
 
949
            else if (spa->wrk == 1) {
 
950
                style.addProperty("style:wrap", "left");
 
951
            }
 
952
            else if (spa->wrk == 2) {
 
953
                style.addProperty("style:wrap", "right");
 
954
            }
 
955
            else if (spa->wrk == 3) {
 
956
                style.addProperty("style:wrap", "biggest");
 
957
            }
 
958
        }
 
959
    }
 
960
    //no information from plcfSpa available 
 
961
    else {
 
962
        style.addProperty("style:wrap", "run-through");
 
963
        if (ds.fBehindDocument()) {
 
964
            style.addProperty("style:run-through", "background");
 
965
        } else {
 
966
            style.addProperty("style:run-through", "foreground");
 
967
        }
 
968
    }
 
969
 
 
970
    //margins are related to text wrapping, 
 
971
    style.addPropertyPt("style:margin-left", ds.dxWrapDistLeft()/12700.);
 
972
    style.addPropertyPt("style:margin-right", ds.dxWrapDistRight()/12700.);
 
973
    style.addPropertyPt("style:margin-top", ds.dyWrapDistTop()/12700.);
 
974
    style.addPropertyPt("style:margin-bottom", ds.dyWrapDistBottom()/12700.);
 
975
 
 
976
    // style:number-wrapped-paragraphs
 
977
    // style:wrap-dynamic-treshold
 
978
}
 
979
 
 
980
void KWordGraphicsHandler::SetAnchorTypeAttribute(DrawingWriter& out)
 
981
{
 
982
    if (out.m_inline) {
 
983
        out.xml.addAttribute("text:anchor-type","as-char");
 
984
    } else {
 
985
        out.xml.addAttribute("text:anchor-type","char");
 
986
    }
 
987
}
 
988
 
 
989
void KWordGraphicsHandler::SetZIndexAttribute(DrawingWriter& out)
 
990
{
 
991
    out.xml.addAttribute("draw:z-index",m_zIndex);
 
992
}
 
993
 
 
994
void KWordGraphicsHandler::parseTextBox(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
 
995
{
 
996
    QString styleName;
 
997
    DrawStyle ds(m_OfficeArtDggContainer,&o);
721
998
    DrawStyle drawStyle(m_OfficeArtDggContainer,NULL,&o);
 
999
    wvWare::Word97::FSPA* spa = out.m_pSpa;
 
1000
    KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
 
1001
 
 
1002
    if (!out.m_bodyDrawing) {
 
1003
        style.setAutoStyleInStylesDotXml(true);
 
1004
    }
 
1005
    defineGraphicProperties(style, ds);
 
1006
    defineWrappingProperties(style, ds, spa);
 
1007
    defineAnchorProperties(style, ds);
 
1008
    styleName = out.styles.insert(style);
 
1009
 
 
1010
    out.xml.startElement("draw:frame");
 
1011
    out.xml.addAttribute("draw:style-name", styleName);
 
1012
    SetAnchorTypeAttribute(out);
 
1013
    SetZIndexAttribute(out);
722
1014
 
723
1015
    switch(drawStyle.txflTextFlow()) {
724
1016
    case 1: //msotxflTtoBA up-down
725
1017
    case 3: //msotxflTtoBN up-down
726
1018
    case 5: //msotxflVertN up-down
727
 
        out.xml.addAttribute("svg:width", out.vLength());
728
 
        out.xml.addAttribute("svg:height",out.hLength());
 
1019
        out.xml.addAttribute("svg:width", mm(out.vLength()));
 
1020
        out.xml.addAttribute("svg:height", mm(out.hLength()));
729
1021
        out.xml.addAttribute("draw:transform","matrix(0 1 -1 0 " +
730
 
                ((Writer *)&out)->hOffset(out.xRight) + " " + out.vOffset() + ")");
 
1022
                mm(((Writer *)&out)->hOffset(out.xRight)) + " " + mm(out.vOffset()) + ")");
731
1023
        break;
732
1024
    case 2: //msotxflBtoT down-up
733
 
        out.xml.addAttribute("svg:width", out.vLength());
734
 
        out.xml.addAttribute("svg:height",out.hLength());
 
1025
        out.xml.addAttribute("svg:width", mm(out.vLength()));
 
1026
        out.xml.addAttribute("svg:height", mm(out.hLength()));
735
1027
        out.xml.addAttribute("draw:transform","matrix(0 -1 1 0 " +
736
 
               out.hOffset() + " " + ((Writer *)&out)->vOffset(out.yBottom) + ")");
 
1028
               mm(out.hOffset()) + " " + mm(((Writer *)&out)->vOffset(out.yBottom)) + ")");
737
1029
         break;
738
1030
    default : //standard text flow
739
 
        out.xml.addAttribute("svg:width", out.hLength());
740
 
        out.xml.addAttribute("svg:height", out.vLength());
741
 
        out.xml.addAttribute("svg:x", out.hOffset());
742
 
        out.xml.addAttribute("svg:y", out.vOffset());
743
 
    }
744
 
 
745
 
    out.xml.startElement("draw:text-box");
746
 
 
747
 
    emit textBoxFound(o.shapeProp.spid , &out.xml);
748
 
 
749
 
    out.xml.endElement(); //draw:text-box
750
 
    out.xml.endElement(); // draw:frame
751
 
}
752
 
 
753
 
void KWordDrawingHandler::processPictureFrame(const MSO::OfficeArtSpContainer&/* o*/,DrawingWriter&/* out*/)
754
 
{
755
 
}
 
1031
        out.xml.addAttribute("svg:width", mm(out.hLength()));
 
1032
        out.xml.addAttribute("svg:height", mm(out.vLength()));
 
1033
        out.xml.addAttribute("svg:x", mm(out.hOffset()));
 
1034
        out.xml.addAttribute("svg:y", mm(out.vOffset()));
 
1035
    }
 
1036
 
 
1037
    out.xml.startElement("draw:text-box");
 
1038
 
 
1039
    emit textBoxFound(o.shapeProp.spid , out.m_bodyDrawing);
 
1040
 
 
1041
    out.xml.endElement(); //draw:text-box
 
1042
    out.xml.endElement(); //draw:frame
 
1043
}
 
1044
 
 
1045
void KWordGraphicsHandler::processRectangle(const MSO::OfficeArtSpContainer& o,DrawingWriter& out)
 
1046
{
 
1047
    QString styleName;
 
1048
    DrawStyle ds(m_OfficeArtDggContainer,&o);
 
1049
    wvWare::Word97::FSPA* spa = out.m_pSpa;
 
1050
    KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
 
1051
 
 
1052
    if (!out.m_bodyDrawing) {
 
1053
        style.setAutoStyleInStylesDotXml(true);
 
1054
    }
 
1055
    defineGraphicProperties(style, ds);
 
1056
    defineWrappingProperties(style, ds, spa);
 
1057
    defineAnchorProperties(style, ds);
 
1058
    styleName = out.styles.insert(style);
 
1059
 
 
1060
    out.xml.startElement("draw:frame");
 
1061
    out.xml.addAttribute("draw:style-name", styleName);
 
1062
    SetAnchorTypeAttribute(out);
 
1063
    SetZIndexAttribute(out);
 
1064
    out.xml.addAttribute("draw:layer", "layout");
 
1065
    out.xml.addAttribute("svg:width", mm(out.hLength()));
 
1066
    out.xml.addAttribute("svg:height", mm(out.vLength()));
 
1067
    out.xml.addAttribute("svg:x", mm(out.hOffset()));
 
1068
    out.xml.addAttribute("svg:y", mm(out.vOffset()));
 
1069
 
 
1070
    out.xml.startElement("draw:text-box");
 
1071
    out.xml.endElement(); //draw:text-box
 
1072
    out.xml.endElement(); //draw:frame
 
1073
}
 
1074
 
 
1075
void KWordGraphicsHandler::processInlinePictureFrame(const MSO::OfficeArtSpContainer& o, DrawingWriter& out)
 
1076
{
 
1077
    kDebug(30513) ;
 
1078
 
 
1079
    QString styleName;
 
1080
    DrawStyle ds(NULL, &o);
 
1081
    KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
 
1082
 
 
1083
    //in case a header or footer is processed, save the style into styles.xml
 
1084
    if (m_document->writingHeader()) {
 
1085
        style.setAutoStyleInStylesDotXml(true);
 
1086
    }
 
1087
    defineGraphicProperties(style, ds);
 
1088
    styleName = out.styles.insert(style);
 
1089
 
 
1090
    QString url;
 
1091
    QString name = m_picNames.value(out.m_rgbUid);
 
1092
    if (!name.isEmpty()) {
 
1093
        url.append("Pictures/");
 
1094
        url.append(name);
 
1095
    }
 
1096
    out.xml.startElement("draw:frame");
 
1097
    if (url.isEmpty()) {
 
1098
        // if the image cannot be found, just place an empty frame
 
1099
        out.xml.endElement(); //draw:frame
 
1100
        return;
 
1101
    }
 
1102
    out.xml.addAttribute("draw:style-name", styleName);
 
1103
    out.xml.addAttribute("text:anchor-type","as-char");
 
1104
 
 
1105
    double hscale = out.m_picf->mx / 1000.0;
 
1106
    double vscale = out.m_picf->my / 1000.0;
 
1107
 
 
1108
    out.xml.addAttributePt("svg:width", twipsToPt(out.m_picf->dxaGoal) * hscale);
 
1109
    out.xml.addAttributePt("svg:height", twipsToPt(out.m_picf->dyaGoal) * vscale);
 
1110
 
 
1111
    //TODO: process border information (complex properties)
 
1112
 
 
1113
    out.xml.startElement("draw:image");
 
1114
    out.xml.addAttribute("xlink:href", url);
 
1115
    out.xml.addAttribute("xlink:type", "simple");
 
1116
    out.xml.addAttribute("xlink:show", "embed");
 
1117
    out.xml.addAttribute("xlink:actuate", "onLoad");
 
1118
    out.xml.endElement(); //draw:image
 
1119
    out.xml.endElement(); //draw:frame
 
1120
    return;
 
1121
}
 
1122
 
 
1123
void KWordGraphicsHandler::processFloatingPictureFrame(const MSO::OfficeArtSpContainer& o, DrawingWriter& out)
 
1124
{
 
1125
    kDebug(30513) ;
 
1126
 
 
1127
    QString styleName;
 
1128
    DrawStyle ds(m_OfficeArtDggContainer, &o);
 
1129
    wvWare::Word97::FSPA* spa = out.m_pSpa;
 
1130
    KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
 
1131
 
 
1132
    //in case a header or footer is processed, save the style into styles.xml
 
1133
    if (m_document->writingHeader()) {
 
1134
        style.setAutoStyleInStylesDotXml(true);
 
1135
    }
 
1136
    defineGraphicProperties(style, ds);
 
1137
    defineWrappingProperties(style, ds, spa);
 
1138
    defineAnchorProperties(style, ds);
 
1139
 
 
1140
    //ODF-1.2: specifies the number of paragraphs that can wrap around a frame
 
1141
    //if wrap mode is in {left, right, parallel, dynamic} and anchor type is in
 
1142
    //{char, paragraph}
 
1143
    if (spa) {
 
1144
        if ((spa->wr != 1) && (spa->wr != 3)) {
 
1145
            style.addProperty("style:number-wrapped-paragraphs", "no-limit");
 
1146
        }
 
1147
    }
 
1148
    styleName = out.styles.insert(style);
 
1149
 
 
1150
    QString url;
 
1151
    if (ds.pib()) {
 
1152
        url = getPicturePath(ds.pib());
 
1153
    }
 
1154
    out.xml.startElement("draw:frame");
 
1155
    if (url.isEmpty()) {
 
1156
        //if the image cannot be found, just place an empty frame
 
1157
        out.xml.endElement(); //draw:frame
 
1158
        return;
 
1159
    }
 
1160
    out.xml.addAttribute("draw:style-name", styleName);
 
1161
    out.xml.addAttribute("text:anchor-type","char");
 
1162
    SetZIndexAttribute(out);
 
1163
    out.xml.addAttribute("svg:width", mm(out.hLength()));
 
1164
    out.xml.addAttribute("svg:height", mm(out.vLength()));
 
1165
    out.xml.addAttribute("svg:x", mm(out.hOffset()));
 
1166
    out.xml.addAttribute("svg:y", mm(out.vOffset()));
 
1167
 
 
1168
    out.xml.startElement("draw:image");
 
1169
    out.xml.addAttribute("xlink:href", url);
 
1170
    out.xml.addAttribute("xlink:type", "simple");
 
1171
    out.xml.addAttribute("xlink:show", "embed");
 
1172
    out.xml.addAttribute("xlink:actuate", "onLoad");
 
1173
    out.xml.endElement(); //draw:image
 
1174
 
 
1175
    //check for user edited wrap points
 
1176
    if (ds.fEditedWrap()) {
 
1177
        QString points;
 
1178
        IMsoArray _v = ds.pWrapPolygonVertices_complex();
 
1179
        if (_v.data.size()) {
 
1180
            //_v.data is an array of POINTs, MS-ODRAW, page 89
 
1181
            QByteArray a, a2;
 
1182
            int* p;
 
1183
 
 
1184
            for (int i = 0, offset = 0; i < _v.nElems; i++, offset += _v.cbElem) {
 
1185
                // x coordinate of this point
 
1186
                a = _v.data.mid(offset, _v.cbElem);
 
1187
                a2 = a.mid(0, _v.cbElem / 2);
 
1188
                p = (int*) a2.data();
 
1189
                points.append(QString::number(twipsToPt(*p)));
 
1190
                points.append(",");
 
1191
                // y coordinate of this point
 
1192
                a2 = a.mid(_v.cbElem / 2, _v.cbElem / 2);
 
1193
                p = (int*) a2.data();
 
1194
                points.append(QString::number(twipsToPt(*p)));
 
1195
                points.append(" ");
 
1196
            }
 
1197
            points.chop(1); //remove last space
 
1198
        }
 
1199
        out.xml.startElement("draw:contour-polygon");
 
1200
        out.xml.addAttribute("draw:points", points);
 
1201
        out.xml.endElement(); //draw:contour-polygon
 
1202
    }
 
1203
    out.xml.endElement(); //draw:frame
 
1204
    return;
 
1205
}
 
1206
 
 
1207
void KWordGraphicsHandler::processLineShape(const MSO::OfficeArtSpContainer& o, DrawingWriter& out)
 
1208
{
 
1209
    kDebug(30513) ;
 
1210
 
 
1211
    QString styleName;
 
1212
    DrawStyle ds(NULL, &o);
 
1213
    KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
 
1214
 
 
1215
    //in case a header or footer is processed, save the style into styles.xml
 
1216
    if (m_document->writingHeader()) {
 
1217
        style.setAutoStyleInStylesDotXml(true);
 
1218
    }
 
1219
    defineGraphicProperties(style, ds);
 
1220
 
 
1221
    //NOTE: also the dxWidthHR propertie may store the width information
 
1222
    float width = ds.pctHR() / 10.0;
 
1223
 
 
1224
    QString hrAlign;
 
1225
    QString xPos = QString::number(0.0f).append("in");
 
1226
    const float base_width = 6.1378;
 
1227
 
 
1228
    switch (ds.alignHR()) {
 
1229
    case wvWare::hAlignLeft:
 
1230
        hrAlign = QString("left");
 
1231
        xPos = QString::number(0.0f).append("in");
 
1232
        break;
 
1233
    case wvWare::hAlignCenter:
 
1234
        hrAlign = QString("center");
 
1235
        xPos = QString::number((base_width / 2.0) - ((width * base_width) / 200.0)).append("in");
 
1236
        break;
 
1237
    case wvWare::hAlignRight:
 
1238
        hrAlign = QString("right");
 
1239
        xPos = QString::number(base_width - (width * base_width) / 100.0).append("in");
 
1240
        break;
 
1241
    }
 
1242
    //process the content of HR specific properties
 
1243
    style.addProperty("draw:textarea-horizontal-align", hrAlign);
 
1244
    style.addProperty("draw:textarea-vertical-align", "top");
 
1245
    if (ds.fNoshadeHR()) {
 
1246
        style.addProperty("draw:shadow", "hidden");
 
1247
    }
 
1248
    else {
 
1249
        style.addProperty("draw:shadow", "visible");
 
1250
    }
 
1251
    styleName = out.styles.insert(style);
 
1252
 
 
1253
    //create a custom shape
 
1254
    out.xml.startElement("draw:custom-shape");
 
1255
    out.xml.addAttribute("draw:style-name", styleName);
 
1256
    SetAnchorTypeAttribute(out);
 
1257
    SetZIndexAttribute(out);
 
1258
 
 
1259
    QString height = QString::number(ds.dxHeightHR() / 1440.0f).append("in");
 
1260
    out.xml.addAttribute("svg:height", height);
 
1261
 
 
1262
    QString width_str = QString::number(width * base_width / 100.0f).append("in");
 
1263
    out.xml.addAttribute("svg:width", width_str);
 
1264
    out.xml.addAttribute("svg:x", xPos);
 
1265
 
 
1266
    //--------------------
 
1267
    out.xml.startElement("draw:enhanced-geometry");
 
1268
    out.xml.addAttribute("svg:viewBox", "0 0 21600 21600");
 
1269
    out.xml.addAttribute("draw:type", "rectangle");
 
1270
    out.xml.addAttribute("draw:enhanced-path", "M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N");
 
1271
    out.xml.endElement(); //enhanced-geometry
 
1272
    out.xml.endElement(); //custom-shape
 
1273
}
 
1274
 
 
1275
void KWordGraphicsHandler::parseFloatingPictures(void)
 
1276
{
 
1277
    kDebug(30513);
 
1278
 
 
1279
    // WordDocument stream equals the Delay stream (DOC)
 
1280
    LEInputStream* in = m_document->wdocument_stream();
 
1281
 
 
1282
    const OfficeArtBStoreContainer* blipStore = m_OfficeArtDggContainer.blipStore.data();
 
1283
    if (blipStore) {
 
1284
        for (int i = 0; i < blipStore->rgfb.size(); i++) {
 
1285
            OfficeArtBStoreContainerFileBlock block = blipStore->rgfb[i];
 
1286
 
 
1287
            //we are looking for the missing content of OfficeArtFBSE
 
1288
            if (block.anon.is<OfficeArtFBSE>()) {
 
1289
                OfficeArtFBSE* fbse = block.anon.get<OfficeArtFBSE>();
 
1290
                if (!fbse->embeddedBlip) {
 
1291
 
 
1292
                    //NOTE: An foDelay value of 0xffffffff specifies that the
 
1293
                    //file is not in the delay stream and cRef must be zero.
 
1294
 
 
1295
                    //NOTE: A cRef value of 0x00000000 specifies an empty slot
 
1296
                    //in the OfficeArtBStoreContainer.
 
1297
 
 
1298
                    if (fbse->foDelay != 0xffffffff) {
 
1299
                        if (!fbse->cRef) {
 
1300
                            kDebug(30513) << "Strange, no references to this BLIP, skipping";
 
1301
                            continue;
 
1302
                        }
 
1303
                        LEInputStream::Mark _zero;
 
1304
                        _zero = in->setMark();
 
1305
                        in->skip(fbse->foDelay);
 
1306
 
 
1307
                        //let's check the record header if there's a BLIP stored
 
1308
                        LEInputStream::Mark _m;
 
1309
                        _m = in->setMark();
 
1310
                        OfficeArtRecordHeader rh;
 
1311
                        parseOfficeArtRecordHeader(*in, rh);
 
1312
                        in->rewind(_m);
 
1313
                        if ( !(rh.recType >= 0xF018 && rh.recType <= 0xF117) ) {
 
1314
                            continue;
 
1315
                        }
 
1316
                        fbse->embeddedBlip = QSharedPointer<OfficeArtBlip>(new OfficeArtBlip(fbse));
 
1317
                        parseOfficeArtBlip(*in, *(fbse->embeddedBlip.data()));
 
1318
                        in->rewind(_zero);
 
1319
                    }
 
1320
                }
 
1321
            } //else there's an OfficeArtBlip inside
 
1322
        }
 
1323
    }
 
1324
    return;
 
1325
}
 
1326
 
 
1327
QMap<QByteArray, QString>
 
1328
KWordGraphicsHandler::createFloatingPictures(KoStore* store, KoXmlWriter* manifest)
 
1329
{
 
1330
    PictureReference ref;
 
1331
    QMap<QByteArray, QString> fileNames;
 
1332
 
 
1333
    const OfficeArtBStoreContainer* blipStore = m_OfficeArtDggContainer.blipStore.data();
 
1334
    if (blipStore) {
 
1335
        store->enterDirectory("Pictures");
 
1336
        foreach (const OfficeArtBStoreContainerFileBlock& block, blipStore->rgfb) {
 
1337
            ref = savePicture(block, store);
 
1338
            if (ref.name.length() == 0) {
 
1339
                kDebug(30513) << "Note: Empty picture reference, probably an empty slot";
 
1340
                continue;
 
1341
            }
 
1342
            manifest->addManifestEntry("Pictures/" + ref.name, ref.mimetype);
 
1343
            fileNames[ref.uid] = ref.name;
 
1344
        }
 
1345
        store->leaveDirectory();
 
1346
    }
 
1347
    return fileNames;
 
1348
}
 
1349
 
 
1350
QString KWordGraphicsHandler::getPicturePath(int pib) const
 
1351
{
 
1352
    int n = pib - 1;
 
1353
    QByteArray rgbUid;
 
1354
 
 
1355
    // return 16 byte rgbuid for this given blip id
 
1356
    const OfficeArtBStoreContainer* blipStore = m_OfficeArtDggContainer.blipStore.data();
 
1357
    if (blipStore) {
 
1358
        if ((n < blipStore->rgfb.size()) &&
 
1359
            blipStore->rgfb[n].anon.is<MSO::OfficeArtFBSE>())
 
1360
        {
 
1361
            rgbUid = blipStore->rgfb[n].anon.get<MSO::OfficeArtFBSE>()->rgbUid;
 
1362
        }
 
1363
        else {
 
1364
            kDebug(30513) << "Could not find image for pib " << pib;
 
1365
        }
 
1366
    }
 
1367
    return rgbUid.length() ? "Pictures/" + m_picNames[rgbUid] : "";
 
1368
}
 
1369
 
756
1370
 
757
1371
#include "graphicshandler.moc"