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

« back to all changes in this revision

Viewing changes to plugins/vectorshape/VectorShape.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-21 15:36:35 UTC
  • mfrom: (1.4.1 upstream) (60.2.11 maverick)
  • Revision ID: james.westby@ubuntu.com-20100921153635-6tejqkiro2u21ydi
Tags: 1:2.2.2-0ubuntu3
Add kubuntu_03_fix-crash-on-closing-sqlite-connection-2.2.2.diff and
kubuntu_04_support-large-memo-values-for-msaccess-2.2.2.diff as
recommended by upstream http://kexi-
project.org/wiki/wikiview/index.php@Kexi2.2_Patches.html#sqlite_stab
ility

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
 *
 
3
 * Copyright (C) 2009 - 2010 Inge Wallin <inge@lysator.liu.se>
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General Public License
 
16
 * along with this library; see the file COPYING.LIB.  If not, write to
 
17
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
18
 * Boston, MA 02110-1301, USA.
 
19
 */
 
20
 
 
21
 
 
22
// Own
 
23
#include "VectorShape.h"
 
24
 
 
25
// Posix
 
26
#include <math.h>
 
27
 
 
28
// Qt
 
29
#include <QPen>
 
30
#include <QPainter>
 
31
#include <QByteArray>
 
32
#include <QBuffer>
 
33
#include <QDataStream>
 
34
#include <QPixmap>
 
35
 
 
36
// KDE
 
37
#include <KDebug>
 
38
 
 
39
// KOffice
 
40
#include "KoUnit.h"
 
41
#include "KoStore.h"
 
42
#include "KoXmlNS.h"
 
43
#include "KoXmlReader.h"
 
44
#include <KoShapeLoadingContext.h>
 
45
#include <KoOdfLoadingContext.h>
 
46
#include <KoShapeSavingContext.h>
 
47
#include <WmfPainter.h>
 
48
 
 
49
// Vector shape
 
50
#include "libemf/EmfParser.h"
 
51
#include "libemf/EmfOutputPainterStrategy.h"
 
52
#include "libemf/EmfOutputDebugStrategy.h"
 
53
 
 
54
 
 
55
VectorShape::VectorShape()
 
56
    : KoFrameShape( KoXmlNS::draw, "image" )
 
57
    , m_type(VectorTypeNone)
 
58
    , m_bytes(0)
 
59
    , m_size(0)
 
60
    , m_ownsBytes(false)
 
61
    , m_printable(true)
 
62
{
 
63
    setShapeId(VectorShape_SHAPEID);
 
64
 
 
65
   // Default size of the shape.
 
66
    KoShape::setSize( QSizeF( CM_TO_POINT( 8 ), CM_TO_POINT( 5 ) ) );
 
67
}
 
68
 
 
69
VectorShape::~VectorShape()
 
70
{
 
71
}
 
72
 
 
73
void  VectorShape::setVectorBytes( char *bytes, int size, bool takeOwnership )
 
74
{
 
75
    if (m_bytes != 0 && m_ownsBytes)
 
76
        delete []m_bytes;
 
77
 
 
78
    m_bytes = bytes;
 
79
    m_size = size;
 
80
    m_ownsBytes = takeOwnership;
 
81
}
 
82
 
 
83
char *VectorShape::vectorBytes()
 
84
{
 
85
    return m_bytes;
 
86
}
 
87
 
 
88
int VectorShape::vectorSize()
 
89
{
 
90
    return m_size;
 
91
}
 
92
 
 
93
 
 
94
void VectorShape::paint(QPainter &painter, const KoViewConverter &converter)
 
95
{
 
96
    applyConversion(painter, converter);
 
97
    draw(painter);
 
98
}
 
99
 
 
100
void VectorShape::paintDecorations(QPainter &painter, const KoViewConverter &converter,
 
101
                                   const KoCanvasBase *canvas)
 
102
{
 
103
    Q_UNUSED(canvas);
 
104
 
 
105
    if (1 || !m_printable) {
 
106
        applyConversion(painter, converter);
 
107
        painter.setRenderHint(QPainter::Antialiasing);
 
108
 
 
109
        draw(painter);
 
110
    }
 
111
}
 
112
 
 
113
void VectorShape::draw(QPainter &painter) const
 
114
{
 
115
    // If the data is uninitialized, e.g. because loading failed, draw the null shape
 
116
    if (m_size == 0) {
 
117
        drawNull(painter);
 
118
        return;
 
119
    }
 
120
 
 
121
    // Actually draw the contents
 
122
    switch (m_type) {
 
123
    case VectorTypeNone:
 
124
        drawNull(painter);
 
125
        break;
 
126
    case VectorTypeWmf:
 
127
        drawWmf(painter);
 
128
        break;
 
129
    case VectorTypeEmf:
 
130
        drawEmf(painter);
 
131
        break;
 
132
    default:
 
133
        drawNull(painter);
 
134
    }
 
135
}
 
136
 
 
137
void VectorShape::drawNull(QPainter &painter) const
 
138
{
 
139
    QRectF  rect(QPointF(0,0), size());
 
140
    painter.save();
 
141
 
 
142
    // Draw a simple cross in a rectangle just to indicate that there is something here.
 
143
    painter.setPen(QPen(QColor(172, 196, 206)));
 
144
    painter.drawRect(rect);
 
145
    painter.drawLine(rect.topLeft(), rect.bottomRight());
 
146
    painter.drawLine(rect.bottomLeft(), rect.topRight());
 
147
 
 
148
    painter.restore();
 
149
}
 
150
 
 
151
void VectorShape::drawWmf(QPainter &painter) const
 
152
{
 
153
    // Debug
 
154
    //drawNull(painter);
 
155
 
 
156
    WmfPainter  wmfPainter;
 
157
    QByteArray  emfArray(m_bytes, m_size);
 
158
 
 
159
    // FIXME: Switch name from emfArray
 
160
    if (!wmfPainter.load(emfArray)) {
 
161
        drawNull(painter);
 
162
        return;
 
163
    }
 
164
 
 
165
    painter.save();
 
166
 
 
167
    // Position the bitmap to the right place and resize it to fit.
 
168
    QRect   wmfBoundingRect = wmfPainter.boundingRect(); // FIXME: Should this be made QRectF?
 
169
    QSizeF  shapeSize       = size();
 
170
 
 
171
    //kDebug(31000) << "wmfBoundingRect: " << wmfBoundingRect;
 
172
    //kDebug(31000) << "shapeSize: "       << shapeSize;
 
173
 
 
174
    // Create a transformation that makes the Wmf fit perfectly into the shape size.
 
175
    painter.scale(shapeSize.width() / wmfBoundingRect.width(),
 
176
                  shapeSize.height() / wmfBoundingRect.height());
 
177
    painter.translate(-wmfBoundingRect.left(), -wmfBoundingRect.top());
 
178
 
 
179
    // Actually paint the WMF.
 
180
    wmfPainter.play(painter, true);
 
181
 
 
182
    painter.restore();
 
183
}
 
184
 
 
185
void VectorShape::drawEmf(QPainter &painter) const
 
186
{
 
187
    // FIXME: Make emfOutput use QSizeF
 
188
    QSize  sizeInt( size().width(), size().height() );
 
189
    //kDebug(31000) << "-------------------------------------------";
 
190
    //kDebug(31000) << "size:     " << sizeInt << size();
 
191
    //kDebug(31000) << "position: " << position();
 
192
    //kDebug(31000) << "-------------------------------------------";
 
193
 
 
194
    // Create a QBuffer to read from...
 
195
    QByteArray  emfArray(m_bytes, m_size);
 
196
    QBuffer     emfBuffer(&emfArray);
 
197
    emfBuffer.open(QIODevice::ReadOnly);
 
198
 
 
199
    // ...but what we really want is a stream.
 
200
    QDataStream  emfStream;
 
201
    emfStream.setDevice(&emfBuffer);
 
202
    emfStream.setByteOrder(QDataStream::LittleEndian);
 
203
 
 
204
    // FIXME: Make it static to save time?
 
205
    Libemf::Parser  emfParser;
 
206
#if 1
 
207
    // Create a new painter output strategy.  Last param = true means keep aspect ratio. 
 
208
    Libemf::OutputPainterStrategy  emfPaintOutput( painter, sizeInt, true );
 
209
    emfParser.setOutput( &emfPaintOutput );
 
210
#else
 
211
    Libemf::OutputDebugStrategy  emfDebugOutput;
 
212
    emfParser.setOutput( &emfDebugOutput );
 
213
#endif
 
214
    emfParser.loadFromStream(emfStream);
 
215
 
 
216
    return;
 
217
}
 
218
 
 
219
void VectorShape::saveOdf(KoShapeSavingContext & context) const
 
220
{
 
221
    Q_UNUSED(context);
 
222
 
 
223
    // FIXME: NYI
 
224
}
 
225
 
 
226
bool VectorShape::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
 
227
{
 
228
    //kDebug(31000) <<"Loading ODF frame in the vector shape. Element = " << element.tagName();
 
229
    loadOdfAttributes(element, context, OdfAllAttributes);
 
230
    return loadOdfFrame(element, context);
 
231
}
 
232
 
 
233
 
 
234
inline static int read32(const char *buffer, const int offset)
 
235
{
 
236
    // little endian
 
237
    int result = (int) buffer[offset];
 
238
    result |= (int) buffer[offset+1] << 8;
 
239
    result |= (int) buffer[offset+2] << 16;
 
240
    result |= (int) buffer[offset+3] << 24;
 
241
 
 
242
    return result;
 
243
}
 
244
 
 
245
// Load the actual contents within the vector shape.
 
246
bool VectorShape::loadOdfFrameElement(const KoXmlElement & element,
 
247
                                      KoShapeLoadingContext &context)
 
248
{
 
249
    //kDebug(31000) <<"Loading ODF element: " << element.tagName();
 
250
 
 
251
    // Get the reference to the vector file.  If there is no href, then just return.
 
252
    const QString href = element.attribute("href");
 
253
    if (href.isEmpty())
 
254
        return false;
 
255
 
 
256
    // Try to open the embedded file.
 
257
    KoStore *store  = context.odfLoadingContext().store();
 
258
    bool     result = store->open(href);
 
259
 
 
260
    if (!result)
 
261
        return false;
 
262
 
 
263
    // Store the size and make a sanity check.
 
264
    // The size of the minimum EMF header record is 88.
 
265
    m_size = store->size();
 
266
    if (m_size < 88) {
 
267
        m_size = 0;
 
268
        return false;
 
269
    }
 
270
 
 
271
    if (m_bytes && m_ownsBytes) {
 
272
        delete []m_bytes;
 
273
        m_bytes = 0;
 
274
    }
 
275
    m_bytes = new char[m_size];
 
276
    m_ownsBytes = true;
 
277
 
 
278
    qint64 bytesRead = store->read(m_bytes, m_size);
 
279
    store->close();
 
280
    if (bytesRead < m_size) {
 
281
        kDebug(31000) << "Too few bytes read: " << bytesRead << " instead of " << m_size;
 
282
        return false;
 
283
    }
 
284
 
 
285
    if (isWmf())
 
286
        m_type = VectorTypeWmf;
 
287
    else if (isEmf())
 
288
        m_type = VectorTypeEmf;
 
289
    else
 
290
        m_type = VectorTypeNone;
 
291
    
 
292
    // Return true if we managed to identify the type.
 
293
    return m_type != VectorTypeNone;
 
294
}
 
295
 
 
296
 
 
297
bool VectorShape::isWmf() const
 
298
{
 
299
    kDebug(31000) << "Check for WMF";
 
300
 
 
301
    if (m_size < 10)
 
302
        return false;
 
303
 
 
304
    // This is how the 'file' command identifies a WMF.
 
305
    if (m_bytes[0] == '\327' && m_bytes[1] == '\315' && m_bytes[2] == '\306' && m_bytes[3] == '\232')
 
306
    {
 
307
        // FIXME: Is this a compressed wmf?  Check it up.
 
308
        kDebug(31000) << "WMF identified: header 1";
 
309
        return true;
 
310
    }
 
311
 
 
312
    if (m_bytes[0] == '\002' && m_bytes[1] == '\000' && m_bytes[2] == '\011' && m_bytes[3] == '\000')
 
313
    {
 
314
        kDebug(31000) << "WMF identified: header 2";
 
315
        return true;
 
316
    }
 
317
 
 
318
    if (m_bytes[0] == '\001' && m_bytes[1] == '\000' && m_bytes[2] == '\011' && m_bytes[3] == '\000')
 
319
    {
 
320
        kDebug(31000) << "WMF identified: header 3";
 
321
        return true;
 
322
    }
 
323
 
 
324
    return false;
 
325
}
 
326
 
 
327
bool VectorShape::isEmf() const
 
328
{
 
329
    kDebug(31000) << "Check for EMF";
 
330
 
 
331
    // This is how the 'file' command identifies an EMF.
 
332
    // 1. Check type
 
333
    qint32 mark = read32(m_bytes, 0);
 
334
    if (mark != 0x00000001) {
 
335
        //kDebug(31000) << "Not an EMF: mark = " << mark << " instead of 0x00000001";
 
336
        return false;
 
337
    }
 
338
 
 
339
    // 2. An EMF has the string " EMF" at the start + offset 40.
 
340
    if (m_size > 44 && m_bytes[40] == ' '
 
341
        && m_bytes[41] == 'E' && m_bytes[42] == 'M' && m_bytes[43] == 'F')
 
342
    {
 
343
        kDebug(31000) << "EMF identified";
 
344
        return true;
 
345
    }
 
346
 
 
347
    return false;
 
348
}
 
349
 
 
350
 
 
351
void VectorShape::setPrintable(bool on)
 
352
{
 
353
    if (m_printable == on)
 
354
        return;
 
355
 
 
356
    m_printable = on;
 
357
    update();
 
358
}
 
359