Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* libmspub
3 : * Version: MPL 1.1 / GPLv2+ / LGPLv2+
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License or as specified alternatively below. You may obtain a copy of
8 : * the License at http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * Major Contributor(s):
16 : * Copyright (C) 2012 Brennan Vincent <brennanv@email.arizona.edu>
17 : * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
18 : *
19 : *
20 : * All Rights Reserved.
21 : *
22 : * For minor contributions see the git repository.
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
26 : * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
27 : * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
28 : * instead of those above.
29 : */
30 :
31 : #include <math.h>
32 : #include "MSPUBCollector.h"
33 : #include "libmspub_utils.h"
34 : #include "MSPUBConstants.h"
35 : #include "MSPUBTypes.h"
36 : #include "PolygonUtils.h"
37 : #include "Coordinate.h"
38 : #pragma GCC diagnostic ignored "-Wpragmas"
39 : #pragma GCC diagnostic ignored "-Wuninitialized"
40 : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
41 :
42 0 : WPXBinaryData &libmspub::MSPUBCollector::addEOTFont(const WPXString &name)
43 : {
44 0 : m_embeddedFonts.push_back(EmbeddedFontInfo(name));
45 0 : return m_embeddedFonts.back().m_blob;
46 : }
47 :
48 0 : void libmspub::MSPUBCollector::setShapePictureRecolor(unsigned seqNum,
49 : const ColorReference &recolor)
50 : {
51 0 : m_shapeInfosBySeqNum[seqNum].m_pictureRecolor = recolor;
52 0 : }
53 :
54 0 : void libmspub::MSPUBCollector::setShapeBeginArrow(unsigned seqNum,
55 : const Arrow &arrow)
56 : {
57 0 : m_shapeInfosBySeqNum[seqNum].m_beginArrow = arrow;
58 0 : }
59 :
60 0 : void libmspub::MSPUBCollector::setShapeVerticalTextAlign(unsigned seqNum,
61 : VerticalAlign va)
62 : {
63 0 : m_shapeInfosBySeqNum[seqNum].m_verticalAlign = va;
64 0 : }
65 :
66 0 : void libmspub::MSPUBCollector::setShapeEndArrow(unsigned seqNum,
67 : const Arrow &arrow)
68 : {
69 0 : m_shapeInfosBySeqNum[seqNum].m_endArrow = arrow;
70 0 : }
71 :
72 0 : void libmspub::MSPUBCollector::setShapeTableInfo(unsigned seqNum,
73 : const TableInfo &ti)
74 : {
75 0 : m_shapeInfosBySeqNum[seqNum].m_tableInfo = ti;
76 0 : }
77 :
78 0 : void libmspub::MSPUBCollector::setShapeNumColumns(unsigned seqNum,
79 : unsigned numColumns)
80 : {
81 0 : m_shapeInfosBySeqNum[seqNum].m_numColumns = numColumns;
82 0 : }
83 :
84 0 : void libmspub::MSPUBCollector::setShapeColumnSpacing(unsigned seqNum,
85 : unsigned spacing)
86 : {
87 0 : m_shapeInfosBySeqNum[seqNum].m_columnSpacing = spacing;
88 0 : }
89 :
90 0 : void libmspub::MSPUBCollector::setShapeStretchBorderArt(unsigned seqNum)
91 : {
92 0 : m_shapeInfosBySeqNum[seqNum].m_stretchBorderArt = true;
93 0 : }
94 :
95 0 : void libmspub::MSPUBCollector::setRectCoordProps(Coordinate coord, WPXPropertyList *props) const
96 : {
97 0 : int xs = coord.m_xs, ys = coord.m_ys, xe = coord.m_xe, ye = coord.m_ye;
98 0 : double x_center = m_width / 2;
99 0 : double y_center = m_height / 2;
100 0 : props->insert("svg:x", x_center + (double)xs / EMUS_IN_INCH);
101 0 : props->insert("svg:y", y_center + (double)ys / EMUS_IN_INCH);
102 0 : props->insert("svg:width", (double)(xe - xs) / EMUS_IN_INCH);
103 0 : props->insert("svg:height", (double)(ye - ys) / EMUS_IN_INCH);
104 0 : }
105 :
106 0 : libmspub::Coordinate getFudgedCoordinates(libmspub::Coordinate coord, const std::vector<libmspub::Line> &lines, bool makeBigger, libmspub::BorderPosition borderPosition)
107 : {
108 0 : libmspub::Coordinate fudged = coord;
109 0 : unsigned topFudge = 0;
110 0 : unsigned rightFudge = 0;
111 0 : unsigned bottomFudge = 0;
112 0 : unsigned leftFudge = 0;
113 0 : switch (borderPosition)
114 : {
115 : case libmspub::HALF_INSIDE_SHAPE:
116 0 : topFudge = (!lines.empty()) ? lines[0].m_widthInEmu / 2 : 0;
117 0 : rightFudge = (lines.size() > 1) ? lines[1].m_widthInEmu / 2 : 0;
118 0 : bottomFudge = (lines.size() > 2) ? lines[2].m_widthInEmu / 2 : 0;
119 0 : leftFudge = (lines.size() > 3) ? lines[3].m_widthInEmu / 2 : 0;
120 0 : break;
121 : case libmspub::OUTSIDE_SHAPE:
122 0 : topFudge = (!lines.empty()) ? lines[0].m_widthInEmu : 0;
123 0 : rightFudge = (lines.size() > 1) ? lines[1].m_widthInEmu : 0;
124 0 : bottomFudge = (lines.size() > 2) ? lines[2].m_widthInEmu : 0;
125 0 : leftFudge = (lines.size() > 3) ? lines[3].m_widthInEmu : 0;
126 0 : break;
127 : case libmspub::INSIDE_SHAPE:
128 : default:
129 0 : break;
130 : }
131 0 : if (makeBigger)
132 : {
133 0 : fudged.m_xs -= leftFudge;
134 0 : fudged.m_xe += rightFudge;
135 0 : fudged.m_ys -= topFudge;
136 0 : fudged.m_ye += bottomFudge;
137 : }
138 : else
139 : {
140 0 : fudged.m_xs += leftFudge;
141 0 : fudged.m_xe -= rightFudge;
142 0 : fudged.m_ys += topFudge;
143 0 : fudged.m_ye -= bottomFudge;
144 : }
145 0 : return fudged;
146 : }
147 :
148 0 : void libmspub::MSPUBCollector::setNextPage(unsigned pageSeqNum)
149 : {
150 0 : m_pageSeqNumsOrdered.push_back(pageSeqNum);
151 0 : }
152 :
153 : #ifndef M_PI
154 : #define M_PI 3.14159265358979323846
155 : #endif
156 :
157 0 : libmspub::MSPUBCollector::MSPUBCollector(libwpg::WPGPaintInterface *painter) :
158 : m_painter(painter), m_contentChunkReferences(), m_width(0), m_height(0),
159 : m_widthSet(false), m_heightSet(false),
160 : m_numPages(0), m_textStringsById(), m_pagesBySeqNum(),
161 : m_images(), m_borderImages(),
162 : m_textColors(), m_fonts(),
163 : m_defaultCharStyles(), m_defaultParaStyles(), m_shapeTypesBySeqNum(),
164 : m_paletteColors(), m_shapeSeqNumsOrdered(),
165 : m_pageSeqNumsByShapeSeqNum(), m_bgShapeSeqNumsByPageSeqNum(),
166 : m_skipIfNotBgSeqNums(),
167 : m_currentShapeGroup(NULL), m_topLevelShapes(),
168 : m_groupsBySeqNum(), m_embeddedFonts(),
169 : m_shapeInfosBySeqNum(), m_masterPages(),
170 : m_shapesWithCoordinatesRotated90(),
171 : m_masterPagesByPageSeqNum(),
172 : m_encoding(), m_tableCellTextEndsVector(), m_stringOffsetsByTextId(),
173 0 : m_calculationValuesSeen(), m_pageSeqNumsOrdered()
174 : {
175 0 : }
176 :
177 0 : void libmspub::MSPUBCollector::setTextStringOffset(
178 : unsigned textId, unsigned offset)
179 : {
180 0 : m_stringOffsetsByTextId[textId] = offset;
181 0 : }
182 :
183 0 : void libmspub::MSPUBCollector::setNextTableCellTextEnds(
184 : const std::vector<unsigned> &ends)
185 : {
186 0 : m_tableCellTextEndsVector.push_back(ends);
187 0 : }
188 :
189 0 : void libmspub::MSPUBCollector::setEncoding(Encoding encoding)
190 : {
191 0 : m_encoding = encoding;
192 0 : }
193 :
194 0 : void libmspub::MSPUBCollector::setShapeShadow(unsigned seqNum, const Shadow &shadow)
195 : {
196 0 : m_shapeInfosBySeqNum[seqNum].m_shadow = shadow;
197 0 : }
198 :
199 0 : void libmspub::noop(const CustomShape *)
200 : {
201 0 : }
202 :
203 0 : void libmspub::MSPUBCollector::setShapeCoordinatesRotated90(unsigned seqNum)
204 : {
205 0 : m_shapesWithCoordinatesRotated90.insert(seqNum);
206 0 : }
207 :
208 0 : void libmspub::MSPUBCollector::setShapeBorderImageId(unsigned seqNum, unsigned id)
209 : {
210 0 : m_shapeInfosBySeqNum[seqNum].m_borderImgIndex = id;
211 0 : }
212 :
213 0 : void libmspub::MSPUBCollector::setShapeCustomPath(unsigned seqNum,
214 : const DynamicCustomShape &shape)
215 : {
216 0 : m_shapeInfosBySeqNum[seqNum].m_customShape = shape;
217 0 : }
218 :
219 0 : void libmspub::MSPUBCollector::beginGroup()
220 : {
221 0 : ShapeGroupElement *tmp = new ShapeGroupElement(m_currentShapeGroup);
222 0 : if (!m_currentShapeGroup)
223 : {
224 0 : m_topLevelShapes.push_back(tmp);
225 : }
226 0 : m_currentShapeGroup = tmp;
227 0 : }
228 :
229 0 : bool libmspub::MSPUBCollector::endGroup()
230 : {
231 0 : if (!m_currentShapeGroup)
232 : {
233 0 : return false;
234 : }
235 0 : m_currentShapeGroup = m_currentShapeGroup->getParent();
236 0 : return true;
237 : }
238 :
239 0 : void libmspub::MSPUBCollector::addShapeLine(unsigned seqNum, Line line)
240 : {
241 0 : m_shapeInfosBySeqNum[seqNum].m_lines.push_back(line);
242 0 : }
243 :
244 0 : void libmspub::MSPUBCollector::setShapeBorderPosition(unsigned seqNum, BorderPosition pos)
245 : {
246 0 : m_shapeInfosBySeqNum[seqNum].m_borderPosition = pos;
247 0 : }
248 :
249 0 : bool libmspub::MSPUBCollector::hasPage(unsigned seqNum) const
250 : {
251 0 : return m_pagesBySeqNum.find(seqNum) != m_pagesBySeqNum.end();
252 : }
253 :
254 0 : void libmspub::MSPUBCollector::setShapeMargins(unsigned seqNum, unsigned left, unsigned top, unsigned right, unsigned bottom)
255 : {
256 0 : m_shapeInfosBySeqNum[seqNum].m_margins = Margins(left, top, right, bottom);
257 0 : }
258 :
259 0 : void libmspub::MSPUBCollector::setPageBgShape(unsigned pageSeqNum, unsigned seqNum)
260 : {
261 0 : m_bgShapeSeqNumsByPageSeqNum[pageSeqNum] = seqNum;
262 0 : }
263 :
264 0 : bool libmspub::MSPUBCollector::setCurrentGroupSeqNum(unsigned seqNum)
265 : {
266 0 : if (!m_currentShapeGroup)
267 : {
268 0 : return false;
269 : }
270 0 : m_currentShapeGroup->setSeqNum(seqNum);
271 0 : m_groupsBySeqNum.insert(std::pair<unsigned, ShapeGroupElement *>(seqNum, m_currentShapeGroup));
272 0 : return true;
273 : }
274 :
275 0 : void libmspub::MSPUBCollector::setShapeOrder(unsigned seqNum)
276 : {
277 0 : ShapeGroupElement *tmp = new ShapeGroupElement(m_currentShapeGroup, seqNum);
278 0 : if (!m_currentShapeGroup)
279 : {
280 0 : m_topLevelShapes.push_back(tmp);
281 : }
282 0 : }
283 :
284 0 : void libmspub::MSPUBCollector::addPaletteColor(Color c)
285 : {
286 0 : m_paletteColors.push_back(c);
287 0 : }
288 :
289 0 : void no_op()
290 : {
291 0 : }
292 :
293 0 : void endShapeGroup(libwpg::WPGPaintInterface *painter)
294 : {
295 0 : painter->endLayer();
296 0 : }
297 :
298 0 : std::vector<int> libmspub::MSPUBCollector::getShapeAdjustValues(const ShapeInfo &info) const
299 : {
300 0 : std::vector<int> ret;
301 0 : boost::shared_ptr<const CustomShape> ptr_shape = info.getCustomShape();
302 0 : if (ptr_shape)
303 : {
304 0 : for (unsigned i = 0; i < ptr_shape->m_numDefaultAdjustValues; ++i)
305 : {
306 0 : ret.push_back(ptr_shape->mp_defaultAdjustValues[i]);
307 : }
308 : }
309 0 : for (std::map<unsigned, int>::const_iterator i = info.m_adjustValuesByIndex.begin();
310 0 : i != info.m_adjustValuesByIndex.end(); ++i)
311 : {
312 0 : unsigned index = i->first;
313 0 : int adjustVal = i->second;
314 0 : for (unsigned j = info.m_adjustValues.size(); j <= index; ++j)
315 : {
316 0 : ret.push_back(0);
317 : }
318 0 : ret[index] = adjustVal;
319 : }
320 0 : return ret;
321 : }
322 :
323 0 : boost::optional<std::vector<libmspub::TextParagraph> > libmspub::MSPUBCollector::getShapeText(const ShapeInfo &info) const
324 : {
325 0 : if (info.m_textId.is_initialized())
326 : {
327 0 : unsigned stringId = info.m_textId.get();
328 0 : const std::vector<TextParagraph> *ptr_str = getIfExists_const(m_textStringsById, stringId);
329 0 : if (ptr_str)
330 : {
331 0 : return *ptr_str;
332 : }
333 : }
334 0 : return boost::optional<std::vector<TextParagraph> >();
335 : }
336 :
337 0 : void libmspub::MSPUBCollector::setupShapeStructures(ShapeGroupElement &elt)
338 : {
339 0 : ShapeInfo *ptr_info = getIfExists(m_shapeInfosBySeqNum, elt.getSeqNum());
340 0 : if (ptr_info)
341 : {
342 0 : if (ptr_info->m_imgIndex.is_initialized())
343 : {
344 0 : unsigned index = ptr_info->m_imgIndex.get();
345 0 : if (index - 1 < m_images.size())
346 : {
347 0 : ptr_info->m_fill = boost::shared_ptr<const Fill>(new ImgFill(index, this, false));
348 : }
349 : }
350 0 : elt.setShapeInfo(*ptr_info);
351 0 : std::pair<bool, bool> flips = ptr_info->m_flips.get_value_or(std::pair<bool, bool>(false, false));
352 0 : VectorTransformation2D flipsTransform = VectorTransformation2D::fromFlips(flips.second, flips.first);
353 0 : double rotation = ptr_info->m_rotation.get_value_or(0);
354 0 : rotation = doubleModulo(rotation, 360);
355 0 : bool rotBackwards = flips.first ^ flips.second;
356 0 : VectorTransformation2D rot = VectorTransformation2D::fromCounterRadians((rotBackwards ? -rotation : rotation) * M_PI / 180);
357 0 : elt.setTransform(rot * flipsTransform);
358 : }
359 0 : }
360 :
361 :
362 0 : boost::function<void(void)> libmspub::MSPUBCollector::paintShape(const ShapeInfo &info, const Coordinate &/* relativeTo*/, const VectorTransformation2D &foldedTransform, bool isGroup, const VectorTransformation2D &thisTransform) const
363 : {
364 0 : std::vector<int> adjustValues = getShapeAdjustValues(info);
365 0 : if (isGroup)
366 : {
367 0 : m_painter->startLayer(WPXPropertyList());
368 0 : return boost::bind(&endShapeGroup, m_painter);
369 : }
370 0 : WPXPropertyList graphicsProps;
371 0 : WPXPropertyListVector graphicsPropsVector;
372 0 : if (info.m_fill)
373 : {
374 0 : graphicsPropsVector = info.m_fill->getProperties(&graphicsProps);
375 : }
376 0 : bool hasStroke = false;
377 0 : bool hasBorderArt = false;
378 0 : boost::optional<unsigned> maybeBorderImg = info.m_borderImgIndex;
379 0 : if (maybeBorderImg.is_initialized() && !info.m_lines.empty())
380 : {
381 0 : hasStroke = true;
382 0 : hasBorderArt = true;
383 : }
384 : else
385 : {
386 0 : for (unsigned i = 0; i < info.m_lines.size(); ++i)
387 : {
388 0 : hasStroke = hasStroke || info.m_lines[i].m_lineExists;
389 0 : if (hasStroke)
390 : {
391 0 : break;
392 : }
393 : }
394 : }
395 0 : WPXString fill = graphicsProps["draw:fill"] ? graphicsProps["draw:fill"]->getStr() : "none";
396 0 : bool hasFill = fill != "none";
397 0 : boost::optional<std::vector<TextParagraph> > maybeText = getShapeText(info);
398 0 : bool hasText = maybeText.is_initialized();
399 : bool makeLayer = hasBorderArt ||
400 0 : (hasStroke && hasFill) || (hasStroke && hasText) || (hasFill && hasText);
401 0 : if (makeLayer)
402 : {
403 0 : m_painter->startLayer(WPXPropertyList());
404 : }
405 0 : graphicsProps.insert("draw:stroke", "none");
406 0 : const Coordinate &coord = info.m_coordinates.get_value_or(Coordinate());
407 : BorderPosition borderPosition =
408 0 : hasBorderArt ? INSIDE_SHAPE : info.m_borderPosition.get_value_or(HALF_INSIDE_SHAPE);
409 0 : ShapeType type = info.m_type.get_value_or(RECTANGLE);
410 0 : if (hasFill)
411 : {
412 : double x, y, height, width;
413 0 : x = coord.getXIn(m_width);
414 0 : y = coord.getYIn(m_height);
415 0 : height = coord.getHeightIn();
416 0 : width = coord.getWidthIn();
417 0 : if (hasBorderArt)
418 : {
419 : double borderImgWidth =
420 0 : static_cast<double>(info.m_lines[0].m_widthInEmu) / EMUS_IN_INCH;
421 0 : if (height > 2 * borderImgWidth && width >= 2 * borderImgWidth)
422 : {
423 0 : x += borderImgWidth;
424 0 : y += borderImgWidth;
425 0 : height -= 2 * borderImgWidth;
426 0 : width -= 2 * borderImgWidth;
427 : }
428 : }
429 0 : if (info.m_pictureRecolor.is_initialized())
430 : {
431 0 : Color obc = info.m_pictureRecolor.get().getFinalColor(m_paletteColors);
432 0 : graphicsProps.insert("draw:color-mode", "greyscale");
433 : graphicsProps.insert("draw:red",
434 0 : static_cast<double>(obc.r) / 255.0, WPX_PERCENT);
435 : graphicsProps.insert("draw:blue",
436 0 : static_cast<double>(obc.b) / 255.0, WPX_PERCENT);
437 : graphicsProps.insert("draw:green",
438 0 : static_cast<double>(obc.g) / 255.0, WPX_PERCENT);
439 : }
440 0 : bool shadowPropsInserted = false;
441 0 : if (info.m_shadow.is_initialized())
442 : {
443 0 : const Shadow &s = info.m_shadow.get();
444 0 : if (!needsEmulation(s))
445 : {
446 0 : shadowPropsInserted = true;
447 0 : graphicsProps.insert("draw:shadow", "visible");
448 : graphicsProps.insert("draw:shadow-offset-x",
449 0 : static_cast<double>(s.m_offsetXInEmu) / EMUS_IN_INCH);
450 : graphicsProps.insert("draw:shadow-offset-y",
451 0 : static_cast<double>(s.m_offsetYInEmu) / EMUS_IN_INCH);
452 : graphicsProps.insert("draw:shadow-color",
453 0 : getColorString(s.m_color.getFinalColor(m_paletteColors)));
454 : graphicsProps.insert("draw:shadow-opacity",
455 0 : s.m_opacity, WPX_PERCENT);
456 : }
457 : // TODO: Emulate shadows that don't conform
458 : // to LibreOffice's range of possible shadows.
459 : }
460 0 : m_painter->setStyle(graphicsProps, graphicsPropsVector);
461 :
462 : writeCustomShape(type, graphicsProps, m_painter, x, y, height, width,
463 : true, foldedTransform,
464 0 : std::vector<Line>(), boost::bind(&libmspub::MSPUBCollector::getCalculationValue, this, info, _1, false, adjustValues), m_paletteColors, info.getCustomShape());
465 0 : if (info.m_pictureRecolor.is_initialized())
466 : {
467 0 : graphicsProps.remove("draw:color-mode");
468 0 : graphicsProps.remove("draw:red");
469 0 : graphicsProps.remove("draw:blue");
470 0 : graphicsProps.remove("draw:green");
471 : }
472 0 : if (shadowPropsInserted)
473 : {
474 0 : graphicsProps.remove("draw:shadow");
475 0 : graphicsProps.remove("draw:shadow-offset-x");
476 0 : graphicsProps.remove("draw:shadow-offset-y");
477 0 : graphicsProps.remove("draw:shadow-color");
478 0 : graphicsProps.remove("draw:shadow-opacity");
479 : }
480 : }
481 0 : const std::vector<Line> &lines = info.m_lines;
482 0 : if (hasStroke)
483 : {
484 0 : if (hasBorderArt)
485 : {
486 0 : bool stretch = info.m_stretchBorderArt;
487 0 : double x = coord.getXIn(m_width);
488 0 : double y = coord.getYIn(m_height);
489 0 : double height = coord.getHeightIn();
490 0 : double width = coord.getWidthIn();
491 : double borderImgWidth =
492 0 : static_cast<double>(info.m_lines[0].m_widthInEmu) / EMUS_IN_INCH;
493 0 : unsigned numImagesHoriz = static_cast<unsigned>(width / borderImgWidth);
494 0 : unsigned numImagesVert = static_cast<unsigned>(height / borderImgWidth);
495 0 : double borderVertTotalPadding = height - numImagesVert * borderImgWidth;
496 0 : double borderHorizTotalPadding = width - numImagesHoriz * borderImgWidth;
497 0 : if (numImagesHoriz >= 2 && numImagesVert >= 2)
498 : {
499 : unsigned numStretchedImagesVert = static_cast<unsigned>(
500 0 : 0.5 + (height - 2 * borderImgWidth) / borderImgWidth);
501 : unsigned numStretchedImagesHoriz = static_cast<unsigned>(
502 0 : 0.5 + (width - 2 * borderImgWidth) / borderImgWidth);
503 : double stretchedImgHeight = stretch ?
504 : (height - 2 * borderImgWidth) / numStretchedImagesVert :
505 0 : borderImgWidth;
506 : double stretchedImgWidth = stretch ?
507 : (width - 2 * borderImgWidth) / numStretchedImagesHoriz :
508 0 : borderImgWidth;
509 0 : if (stretch)
510 : {
511 0 : numImagesVert = 2 + numStretchedImagesVert;
512 0 : numImagesHoriz = 2 + numStretchedImagesHoriz;
513 : }
514 0 : double borderVertPadding = borderVertTotalPadding / (numImagesVert - 1);
515 0 : double borderHorizPadding = borderHorizTotalPadding / (numImagesHoriz - 1);
516 0 : const BorderArtInfo &ba = m_borderImages[maybeBorderImg.get()];
517 0 : if (!ba.m_offsets.empty())
518 : {
519 0 : WPXPropertyList baProps;
520 0 : baProps.insert("draw:stroke", "none");
521 0 : baProps.insert("draw:fill", "solid");
522 0 : baProps.insert("draw:fill-color", "#ffffff");
523 0 : m_painter->setStyle(baProps, WPXPropertyListVector());
524 0 : WPXPropertyList topRectProps;
525 0 : topRectProps.insert("svg:x", x);
526 0 : topRectProps.insert("svg:y", y);
527 0 : topRectProps.insert("svg:height", borderImgWidth);
528 0 : topRectProps.insert("svg:width", width);
529 0 : m_painter->drawRectangle(topRectProps);
530 0 : WPXPropertyList rightRectProps;
531 0 : rightRectProps.insert("svg:x", x + width - borderImgWidth);
532 0 : rightRectProps.insert("svg:y", y);
533 0 : rightRectProps.insert("svg:height", height);
534 0 : rightRectProps.insert("svg:width", borderImgWidth);
535 0 : m_painter->drawRectangle(rightRectProps);
536 0 : WPXPropertyList botRectProps;
537 0 : botRectProps.insert("svg:x", x);
538 0 : botRectProps.insert("svg:y", y + height - borderImgWidth);
539 0 : botRectProps.insert("svg:height", borderImgWidth);
540 0 : botRectProps.insert("svg:width", width);
541 0 : m_painter->drawRectangle(botRectProps);
542 0 : WPXPropertyList leftRectProps;
543 0 : leftRectProps.insert("svg:x", x);
544 0 : leftRectProps.insert("svg:y", y);
545 0 : leftRectProps.insert("svg:height", height);
546 0 : leftRectProps.insert("svg:width", borderImgWidth);
547 0 : m_painter->drawRectangle(leftRectProps);
548 0 : std::vector<unsigned>::const_iterator iOffset = ba.m_offsets.begin();
549 0 : boost::optional<Color> oneBitColor;
550 0 : if (info.m_lineBackColor.is_initialized())
551 : {
552 0 : oneBitColor = info.m_lineBackColor.get().getFinalColor(m_paletteColors);
553 : }
554 : // top left
555 : unsigned iOrdOff = find(ba.m_offsetsOrdered.begin(),
556 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
557 0 : if (iOrdOff < ba.m_images.size())
558 : {
559 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
560 : writeImage(x, y, borderImgWidth, borderImgWidth,
561 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
562 : }
563 0 : if (iOffset + 1 != ba.m_offsets.end())
564 : {
565 0 : ++iOffset;
566 : }
567 : // top
568 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
569 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
570 0 : if (iOrdOff < ba.m_images.size())
571 : {
572 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
573 0 : for (unsigned iTop = 1; iTop < numImagesHoriz - 1; ++iTop)
574 : {
575 : double imgX = stretch ?
576 : x + borderImgWidth + (iTop - 1) * stretchedImgWidth :
577 0 : x + iTop * (borderImgWidth + borderHorizPadding);
578 : writeImage(imgX, y,
579 : borderImgWidth, stretchedImgWidth,
580 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
581 : }
582 : }
583 0 : if (iOffset + 1 != ba.m_offsets.end())
584 : {
585 0 : ++iOffset;
586 : }
587 : // top right
588 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
589 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
590 0 : if (iOrdOff < ba.m_images.size())
591 : {
592 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
593 : writeImage(x + width - borderImgWidth, y,
594 : borderImgWidth, borderImgWidth,
595 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
596 : }
597 0 : if (iOffset + 1 != ba.m_offsets.end())
598 : {
599 0 : ++iOffset;
600 : }
601 : // right
602 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
603 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
604 0 : if (iOrdOff < ba.m_images.size())
605 : {
606 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
607 0 : for (unsigned iRight = 1; iRight < numImagesVert - 1; ++iRight)
608 : {
609 : double imgY = stretch ?
610 : y + borderImgWidth + (iRight - 1) * stretchedImgHeight :
611 0 : y + iRight * (borderImgWidth + borderVertPadding);
612 : writeImage(x + width - borderImgWidth,
613 : imgY,
614 : stretchedImgHeight, borderImgWidth,
615 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
616 : }
617 : }
618 0 : if (iOffset + 1 != ba.m_offsets.end())
619 : {
620 0 : ++iOffset;
621 : }
622 : // bottom right
623 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
624 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
625 0 : if (iOrdOff < ba.m_images.size())
626 : {
627 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
628 : writeImage(x + width - borderImgWidth,
629 : y + height - borderImgWidth,
630 : borderImgWidth, borderImgWidth,
631 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
632 : }
633 0 : if (iOffset + 1 != ba.m_offsets.end())
634 : {
635 0 : ++iOffset;
636 : }
637 : // bottom
638 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
639 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
640 0 : if (iOrdOff < ba.m_images.size())
641 : {
642 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
643 0 : for (unsigned iBot = 1; iBot < numImagesHoriz - 1; ++iBot)
644 : {
645 : double imgX = stretch ?
646 : x + width - borderImgWidth - iBot * stretchedImgWidth :
647 0 : x + width - borderImgWidth - iBot * (borderImgWidth + borderHorizPadding);
648 : writeImage(
649 : imgX, y + height - borderImgWidth,
650 : borderImgWidth, stretchedImgWidth,
651 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
652 : }
653 : }
654 0 : if (iOffset + 1 != ba.m_offsets.end())
655 : {
656 0 : ++iOffset;
657 : }
658 : // bottom left
659 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
660 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
661 0 : if (iOrdOff < ba.m_images.size())
662 : {
663 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
664 : writeImage(x, y + height - borderImgWidth,
665 : borderImgWidth, borderImgWidth,
666 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
667 : }
668 0 : if (iOffset + 1 != ba.m_offsets.end())
669 : {
670 0 : ++iOffset;
671 : }
672 : // left
673 : iOrdOff = find(ba.m_offsetsOrdered.begin(),
674 0 : ba.m_offsetsOrdered.end(), *iOffset) - ba.m_offsetsOrdered.begin();
675 0 : if (iOrdOff < ba.m_images.size())
676 : {
677 0 : const BorderImgInfo &bi = ba.m_images[iOrdOff];
678 0 : for (unsigned iLeft = 1; iLeft < numImagesVert - 1; ++iLeft)
679 : {
680 : double imgY = stretch ?
681 : y + height - borderImgWidth - iLeft * stretchedImgHeight :
682 : y + height - borderImgWidth -
683 0 : iLeft * (borderImgWidth + borderVertPadding);
684 : writeImage(x, imgY, stretchedImgHeight, borderImgWidth,
685 0 : bi.m_type, bi.m_imgBlob, oneBitColor);
686 : }
687 0 : }
688 : }
689 : }
690 : }
691 : else
692 : {
693 0 : Coordinate strokeCoord = isShapeTypeRectangle(type) ?
694 0 : getFudgedCoordinates(coord, lines, true, borderPosition) : coord;
695 : double x, y, height, width;
696 0 : x = strokeCoord.getXIn(m_width);
697 0 : y = strokeCoord.getYIn(m_height);
698 0 : height = strokeCoord.getHeightIn();
699 0 : width = strokeCoord.getWidthIn();
700 0 : graphicsProps.insert("draw:fill", "none");
701 0 : if (info.m_dash.is_initialized() && !info.m_dash.get().m_dots.empty())
702 : {
703 0 : const Dash &dash = info.m_dash.get();
704 0 : graphicsProps.insert("draw:stroke", "dash");
705 0 : graphicsProps.insert("draw:distance", dash.m_distance, WPX_INCH);
706 0 : switch (dash.m_dotStyle)
707 : {
708 : case ROUND_DOT:
709 0 : graphicsProps.insert("svg:stroke-linecap", "round");
710 0 : break;
711 : case RECT_DOT:
712 0 : graphicsProps.insert("svg:stroke-linecap", "rect");
713 0 : break;
714 : default:
715 0 : break;
716 : }
717 0 : for (unsigned i = 0; i < dash.m_dots.size(); ++i)
718 : {
719 0 : WPXString dots;
720 0 : dots.sprintf("draw:dots%d", i + 1);
721 0 : graphicsProps.insert(dots.cstr(), static_cast<int>(dash.m_dots[i].m_count));
722 0 : if (dash.m_dots[i].m_length.is_initialized())
723 : {
724 0 : WPXString length;
725 0 : length.sprintf("draw:dots%d-length", i + 1);
726 0 : graphicsProps.insert(length.cstr(), dash.m_dots[i].m_length.get(), WPX_INCH);
727 : }
728 0 : }
729 : }
730 : else
731 : {
732 0 : graphicsProps.insert("draw:stroke", "solid");
733 : }
734 0 : m_painter->setStyle(graphicsProps, graphicsPropsVector);
735 : writeCustomShape(type, graphicsProps, m_painter, x, y, height, width,
736 : false, foldedTransform, lines,
737 : boost::bind(
738 : &libmspub::MSPUBCollector::getCalculationValue, this, info, _1, false, adjustValues
739 : ),
740 0 : m_paletteColors, info.getCustomShape());
741 : }
742 : }
743 0 : if (hasText)
744 : {
745 0 : const std::vector<TextParagraph> &text = maybeText.get();
746 0 : graphicsProps.insert("draw:fill", "none");
747 0 : Coordinate textCoord = isShapeTypeRectangle(type) ?
748 0 : getFudgedCoordinates(coord, lines, false, borderPosition) : coord;
749 0 : m_painter->setStyle(graphicsProps, graphicsPropsVector);
750 0 : WPXPropertyList props;
751 0 : setRectCoordProps(textCoord, &props);
752 0 : double textRotation = thisTransform.getRotation();
753 0 : if (textRotation != 0)
754 : {
755 0 : props.insert("libwpg:rotate", textRotation * 180 / M_PI);
756 : }
757 0 : Margins margins = info.m_margins.get_value_or(Margins());
758 0 : props.insert("fo:padding-left", (double)margins.m_left / EMUS_IN_INCH);
759 0 : props.insert("fo:padding-top", (double)margins.m_top / EMUS_IN_INCH);
760 0 : props.insert("fo:padding-right", (double)margins.m_right / EMUS_IN_INCH);
761 0 : props.insert("fo:padding-bottom", (double)margins.m_bottom / EMUS_IN_INCH);
762 0 : if(info.m_verticalAlign.is_initialized())
763 : {
764 0 : switch (info.m_verticalAlign.get())
765 : {
766 : default:
767 : case TOP:
768 0 : props.insert("draw:textarea-vertical-align", "top");
769 0 : break;
770 : case MIDDLE:
771 0 : props.insert("draw:textarea-vertical-align", "middle");
772 0 : break;
773 : case BOTTOM:
774 0 : props.insert("draw:textarea-vertical-align", "bottom");
775 0 : break;
776 : }
777 : }
778 0 : m_painter->startTextObject(props, WPXPropertyListVector());
779 0 : for (unsigned i_lines = 0; i_lines < text.size(); ++i_lines)
780 : {
781 0 : WPXPropertyList paraProps = getParaStyleProps(text[i_lines].style, text[i_lines].style.m_defaultCharStyleIndex);
782 0 : m_painter->startTextLine(paraProps);
783 0 : for (unsigned i_spans = 0; i_spans < text[i_lines].spans.size(); ++i_spans)
784 : {
785 0 : WPXString textString;
786 0 : appendCharacters(textString, text[i_lines].spans[i_spans].chars,
787 0 : m_encoding.get_value_or(UTF_16));
788 0 : WPXPropertyList charProps = getCharStyleProps(text[i_lines].spans[i_spans].style, text[i_lines].style.m_defaultCharStyleIndex);
789 0 : m_painter->startTextSpan(charProps);
790 0 : m_painter->insertText(textString);
791 0 : m_painter->endTextSpan();
792 0 : }
793 0 : m_painter->endTextLine();
794 0 : }
795 0 : m_painter->endTextObject();
796 : }
797 0 : if (makeLayer)
798 : {
799 0 : m_painter->endLayer();
800 : }
801 0 : return &no_op;
802 : }
803 :
804 0 : void libmspub::MSPUBCollector::setShapeLineBackColor(unsigned shapeSeqNum,
805 : ColorReference backColor)
806 : {
807 0 : m_shapeInfosBySeqNum[shapeSeqNum].m_lineBackColor = backColor;
808 0 : }
809 :
810 0 : void libmspub::MSPUBCollector::writeImage(double x, double y,
811 : double height, double width, ImgType type, const WPXBinaryData &blob,
812 : boost::optional<Color> oneBitColor) const
813 : {
814 0 : WPXPropertyList props;
815 0 : if (oneBitColor.is_initialized())
816 : {
817 0 : Color obc = oneBitColor.get();
818 0 : props.insert("draw:color-mode", "greyscale");
819 0 : props.insert("draw:red", static_cast<double>(obc.r) / 255.0, WPX_PERCENT);
820 0 : props.insert("draw:blue", static_cast<double>(obc.b) / 255.0, WPX_PERCENT);
821 0 : props.insert("draw:green", static_cast<double>(obc.g) / 255.0, WPX_PERCENT);
822 : }
823 0 : props.insert("svg:x", x);
824 0 : props.insert("svg:y", y);
825 0 : props.insert("svg:width", width);
826 0 : props.insert("svg:height", height);
827 0 : props.insert("libwpg:mime-type", mimeByImgType(type));
828 0 : m_painter->drawGraphicObject(props, blob);
829 0 : }
830 :
831 0 : double libmspub::MSPUBCollector::getSpecialValue(const ShapeInfo &info, const CustomShape &shape, int arg, const std::vector<int> &adjustValues) const
832 : {
833 0 : if (PROP_ADJUST_VAL_FIRST <= arg && PROP_ADJUST_VAL_LAST >= arg)
834 : {
835 0 : unsigned adjustIndex = arg - PROP_ADJUST_VAL_FIRST;
836 0 : if (adjustIndex < adjustValues.size())
837 : {
838 0 : if ((shape.m_adjustShiftMask >> adjustIndex) & 0x1)
839 : {
840 0 : return adjustValues[adjustIndex] >> 16;
841 : }
842 0 : return adjustValues[adjustIndex];
843 : }
844 0 : return 0;
845 : }
846 0 : if (arg == ASPECT_RATIO)
847 : {
848 0 : const Coordinate &coord = info.m_coordinates.get_value_or(Coordinate());
849 0 : return (double)coord.getWidthIn() / coord.getHeightIn();
850 : }
851 0 : if (arg & OTHER_CALC_VAL)
852 : {
853 0 : return getCalculationValue(info, arg & 0xff, true, adjustValues);
854 : }
855 0 : switch (arg)
856 : {
857 : case PROP_GEO_LEFT:
858 0 : return 0;
859 : case PROP_GEO_TOP:
860 0 : return 0;
861 : case PROP_GEO_RIGHT:
862 0 : return shape.m_coordWidth;
863 : case PROP_GEO_BOTTOM:
864 0 : return shape.m_coordHeight;
865 : default:
866 0 : break;
867 : }
868 0 : return 0;
869 : }
870 :
871 0 : double libmspub::MSPUBCollector::getCalculationValue(const ShapeInfo &info, unsigned index, bool recursiveEntry, const std::vector<int> &adjustValues) const
872 : {
873 0 : boost::shared_ptr<const CustomShape> p_shape = info.getCustomShape();
874 0 : if (! p_shape)
875 : {
876 0 : return 0;
877 : }
878 0 : const CustomShape &shape = *p_shape;
879 0 : if (index >= shape.m_numCalculations)
880 : {
881 0 : return 0;
882 : }
883 0 : if (! recursiveEntry)
884 : {
885 0 : m_calculationValuesSeen.clear();
886 0 : m_calculationValuesSeen.resize(shape.m_numCalculations);
887 : }
888 0 : if (m_calculationValuesSeen[index])
889 : {
890 : //recursion detected. The simplest way to avoid infinite recursion, at the "cost"
891 : // of making custom shape parsing not Turing-complete ;), is to ban recursion entirely.
892 0 : return 0;
893 : }
894 0 : m_calculationValuesSeen[index] = true;
895 :
896 0 : const Calculation &c = shape.mp_calculations[index];
897 0 : bool oneSpecial = (c.m_flags & 0x2000) != 0;
898 0 : bool twoSpecial = (c.m_flags & 0x4000) != 0;
899 0 : bool threeSpecial = (c.m_flags & 0x8000) != 0;
900 :
901 0 : double valOne = oneSpecial ? getSpecialValue(info, shape, c.m_argOne, adjustValues) : c.m_argOne;
902 0 : double valTwo = twoSpecial ? getSpecialValue(info, shape, c.m_argTwo, adjustValues) : c.m_argTwo;
903 0 : double valThree = threeSpecial ? getSpecialValue(info, shape, c.m_argThree, adjustValues) : c.m_argThree;
904 0 : m_calculationValuesSeen[index] = false;
905 0 : switch (c.m_flags & 0xFF)
906 : {
907 : case 0:
908 : case 14:
909 0 : return valOne + valTwo - valThree;
910 : case 1:
911 0 : return valOne * valTwo / (valThree == 0 ? 1 : valThree);
912 : case 2:
913 0 : return (valOne + valTwo) / 2;
914 : case 3:
915 0 : return fabs(valOne);
916 : case 4:
917 0 : return std::min(valOne, valTwo);
918 : case 5:
919 0 : return std::max(valOne, valTwo);
920 : case 6:
921 0 : return valOne ? valTwo : valThree;
922 : case 7:
923 0 : return sqrt(valOne * valTwo * valThree);
924 : case 8:
925 0 : return atan2(valTwo, valOne) / (M_PI / 180);
926 : case 9:
927 0 : return valOne * sin(valTwo * (M_PI / 180) );
928 : case 10:
929 0 : return valOne * cos(valTwo * (M_PI / 180) );
930 : case 11:
931 0 : return valOne * cos(atan2(valThree, valTwo));
932 : case 12:
933 0 : return valOne * sin(atan2(valThree, valTwo));
934 : case 13:
935 0 : return sqrt(valOne);
936 : case 15:
937 0 : return valThree * sqrt(1 - (valOne / valTwo) * (valOne / valTwo));
938 : case 16:
939 0 : return valOne * tan(valTwo);
940 : case 0x80:
941 0 : return sqrt(valThree * valThree - valOne * valOne);
942 : case 0x81:
943 0 : return (cos(valThree * (M_PI / 180)) * (valOne - 10800) + sin(valThree * (M_PI / 180)) * (valTwo - 10800)) + 10800;
944 : case 0x82:
945 0 : return -(sin(valThree * (M_PI / 180)) * (valOne - 10800) - cos(valThree * (M_PI / 180)) * (valTwo - 10800)) + 10800;
946 : default:
947 0 : return 0;
948 0 : }
949 : }
950 :
951 0 : libmspub::MSPUBCollector::~MSPUBCollector()
952 : {
953 0 : }
954 :
955 0 : void libmspub::MSPUBCollector::setShapeRotation(unsigned seqNum, double rotation)
956 : {
957 0 : m_shapeInfosBySeqNum[seqNum].m_rotation = rotation;
958 0 : }
959 :
960 0 : void libmspub::MSPUBCollector::setShapeFlip(unsigned seqNum, bool flipVertical, bool flipHorizontal)
961 : {
962 0 : m_shapeInfosBySeqNum[seqNum].m_flips = std::pair<bool, bool>(flipVertical, flipHorizontal);
963 0 : }
964 :
965 0 : void libmspub::MSPUBCollector::setShapeType(unsigned seqNum, ShapeType type)
966 : {
967 0 : m_shapeInfosBySeqNum[seqNum].m_type = type;
968 0 : }
969 :
970 0 : void libmspub::MSPUBCollector::setAdjustValue(unsigned seqNum, unsigned index, int adjust)
971 : {
972 0 : m_shapeInfosBySeqNum[seqNum].m_adjustValuesByIndex[index] = adjust;
973 0 : }
974 :
975 0 : void libmspub::MSPUBCollector::addDefaultCharacterStyle(const CharacterStyle &st)
976 : {
977 0 : m_defaultCharStyles.push_back(st);
978 0 : }
979 :
980 0 : void libmspub::MSPUBCollector::addDefaultParagraphStyle(const ParagraphStyle &st)
981 : {
982 0 : m_defaultParaStyles.push_back(st);
983 0 : }
984 :
985 0 : bool libmspub::MSPUBCollector::addPage(unsigned seqNum)
986 : {
987 0 : if (! (m_widthSet && m_heightSet) )
988 : {
989 0 : return false;
990 : }
991 : MSPUB_DEBUG_MSG(("Adding page of seqnum 0x%x\n", seqNum));
992 0 : m_pagesBySeqNum[seqNum] = PageInfo();
993 0 : return true;
994 : }
995 :
996 0 : void libmspub::MSPUBCollector::addTextShape(unsigned stringId, unsigned seqNum)
997 : {
998 0 : m_shapeInfosBySeqNum[seqNum].m_textId = stringId;
999 0 : }
1000 :
1001 0 : void libmspub::MSPUBCollector::setShapeImgIndex(unsigned seqNum, unsigned index)
1002 : {
1003 : MSPUB_DEBUG_MSG(("Setting image index of shape with seqnum 0x%x to 0x%x\n", seqNum, index));
1004 0 : m_shapeInfosBySeqNum[seqNum].m_imgIndex = index;
1005 0 : }
1006 :
1007 0 : void libmspub::MSPUBCollector::setShapeDash(unsigned seqNum, const Dash &dash)
1008 : {
1009 0 : m_shapeInfosBySeqNum[seqNum].m_dash = dash;
1010 0 : }
1011 :
1012 0 : void libmspub::MSPUBCollector::setShapeFill(unsigned seqNum, boost::shared_ptr<Fill> fill, bool skipIfNotBg)
1013 : {
1014 0 : m_shapeInfosBySeqNum[seqNum].m_fill = fill;
1015 0 : if (skipIfNotBg)
1016 : {
1017 0 : m_skipIfNotBgSeqNums.insert(seqNum);
1018 : }
1019 0 : }
1020 :
1021 0 : void libmspub::MSPUBCollector::setShapeCoordinatesInEmu(unsigned seqNum, int xs, int ys, int xe, int ye)
1022 : {
1023 0 : m_shapeInfosBySeqNum[seqNum].m_coordinates = Coordinate(xs, ys, xe, ye);
1024 0 : }
1025 :
1026 0 : void libmspub::MSPUBCollector::addFont(std::vector<unsigned char> name)
1027 : {
1028 0 : m_fonts.push_back(name);
1029 0 : }
1030 :
1031 0 : WPXPropertyList libmspub::MSPUBCollector::getParaStyleProps(const ParagraphStyle &style, boost::optional<unsigned> defaultParaStyleIndex) const
1032 : {
1033 0 : ParagraphStyle _nothing;
1034 0 : const ParagraphStyle &defaultStyle = defaultParaStyleIndex.is_initialized() && defaultParaStyleIndex.get() < m_defaultParaStyles.size() ? m_defaultParaStyles[defaultParaStyleIndex.get()] : _nothing;
1035 0 : WPXPropertyList ret;
1036 : Alignment align = style.m_align.get_value_or(
1037 0 : defaultStyle.m_align.get_value_or(LEFT));
1038 0 : switch (align)
1039 : {
1040 : case RIGHT:
1041 0 : ret.insert("fo:text-align", "right");
1042 0 : break;
1043 : case CENTER:
1044 0 : ret.insert("fo:text-align", "center");
1045 0 : break;
1046 : case JUSTIFY:
1047 0 : ret.insert("fo:text-align", "justify");
1048 0 : break;
1049 : case LEFT:
1050 : default:
1051 0 : ret.insert("fo:text-align", "left");
1052 0 : break;
1053 : }
1054 : LineSpacingInfo info = style.m_lineSpacing.get_value_or(
1055 0 : defaultStyle.m_lineSpacing.get_value_or(LineSpacingInfo()));
1056 0 : LineSpacingType lineSpacingType = info.m_type;
1057 0 : double lineSpacing = info.m_amount;
1058 0 : if (!(lineSpacingType == LINE_SPACING_SP && lineSpacing == 1))
1059 : {
1060 0 : if (lineSpacingType == LINE_SPACING_SP)
1061 : {
1062 0 : ret.insert("fo:line-height", lineSpacing, WPX_PERCENT);
1063 : }
1064 0 : else if (lineSpacingType == LINE_SPACING_PT)
1065 : {
1066 0 : ret.insert("fo:line-height", lineSpacing, WPX_POINT);
1067 : }
1068 : }
1069 : unsigned spaceAfterEmu = style.m_spaceAfterEmu.get_value_or(
1070 0 : defaultStyle.m_spaceAfterEmu.get_value_or(0));
1071 : unsigned spaceBeforeEmu = style.m_spaceBeforeEmu.get_value_or(
1072 0 : defaultStyle.m_spaceBeforeEmu.get_value_or(0));
1073 : unsigned firstLineIndentEmu = style.m_firstLineIndentEmu.get_value_or(
1074 0 : defaultStyle.m_firstLineIndentEmu.get_value_or(0));
1075 : unsigned leftIndentEmu = style.m_leftIndentEmu.get_value_or(
1076 0 : defaultStyle.m_leftIndentEmu.get_value_or(0));
1077 : unsigned rightIndentEmu = style.m_rightIndentEmu.get_value_or(
1078 0 : defaultStyle.m_rightIndentEmu.get_value_or(0));
1079 0 : if (spaceAfterEmu != 0)
1080 : {
1081 0 : ret.insert("fo:margin-bottom", (double)spaceAfterEmu / EMUS_IN_INCH);
1082 : }
1083 0 : if (spaceBeforeEmu != 0)
1084 : {
1085 0 : ret.insert("fo:margin-top", (double)spaceBeforeEmu / EMUS_IN_INCH);
1086 : }
1087 0 : if (firstLineIndentEmu != 0)
1088 : {
1089 0 : ret.insert("fo:text-indent", (double)firstLineIndentEmu / EMUS_IN_INCH);
1090 : }
1091 0 : if (leftIndentEmu != 0)
1092 : {
1093 0 : ret.insert("fo:margin-left", (double)leftIndentEmu / EMUS_IN_INCH);
1094 : }
1095 0 : if (rightIndentEmu != 0)
1096 : {
1097 0 : ret.insert("fo:margin-right", (double)rightIndentEmu / EMUS_IN_INCH);
1098 : }
1099 0 : return ret;
1100 : }
1101 :
1102 0 : WPXPropertyList libmspub::MSPUBCollector::getCharStyleProps(const CharacterStyle &style, boost::optional<unsigned> defaultCharStyleIndex) const
1103 : {
1104 0 : CharacterStyle _nothing = CharacterStyle(false, false, false);
1105 0 : const CharacterStyle &defaultCharStyle = defaultCharStyleIndex.is_initialized() && defaultCharStyleIndex.get() < m_defaultCharStyles.size() ? m_defaultCharStyles[defaultCharStyleIndex.get()] : _nothing;
1106 0 : WPXPropertyList ret;
1107 0 : if (style.italic ^ defaultCharStyle.italic)
1108 : {
1109 0 : ret.insert("fo:font-style", "italic");
1110 : }
1111 0 : if (style.bold ^ defaultCharStyle.bold)
1112 : {
1113 0 : ret.insert("fo:font-weight", "bold");
1114 : }
1115 0 : if (style.underline ^ defaultCharStyle.underline)
1116 : {
1117 0 : ret.insert("style:text-underline-type", "single");
1118 : }
1119 0 : if (style.textSizeInPt.is_initialized())
1120 : {
1121 0 : ret.insert("fo:font-size", style.textSizeInPt.get() / POINTS_IN_INCH);
1122 : }
1123 0 : else if (defaultCharStyle.textSizeInPt.is_initialized())
1124 : {
1125 0 : ret.insert("fo:font-size", defaultCharStyle.textSizeInPt.get()
1126 0 : / POINTS_IN_INCH);
1127 : }
1128 0 : if (style.colorIndex >= 0 && (size_t)style.colorIndex < m_textColors.size())
1129 : {
1130 0 : ret.insert("fo:color", getColorString(m_textColors[style.colorIndex].getFinalColor(m_paletteColors)));
1131 : }
1132 0 : else if (defaultCharStyle.colorIndex >= 0 && (size_t)defaultCharStyle.colorIndex < m_textColors.size())
1133 : {
1134 0 : ret.insert("fo:color", getColorString(m_textColors[defaultCharStyle.colorIndex].getFinalColor(m_paletteColors)));
1135 : }
1136 : else
1137 : {
1138 0 : ret.insert("fo:color", getColorString(Color(0, 0, 0))); // default color is black
1139 : }
1140 0 : if (style.fontIndex.is_initialized() &&
1141 0 : style.fontIndex.get() < m_fonts.size())
1142 : {
1143 0 : WPXString str;
1144 0 : appendCharacters(str, m_fonts[style.fontIndex.get()],
1145 0 : m_encoding.get_value_or(UTF_16));
1146 0 : ret.insert("style:font-name", str);
1147 : }
1148 0 : else if (defaultCharStyle.fontIndex.is_initialized() &&
1149 0 : defaultCharStyle.fontIndex.get() < m_fonts.size())
1150 : {
1151 0 : WPXString str;
1152 0 : appendCharacters(str, m_fonts[defaultCharStyle.fontIndex.get()],
1153 0 : m_encoding.get_value_or(UTF_16));
1154 0 : ret.insert("style:font-name", str);
1155 : }
1156 0 : else if (!m_fonts.empty())
1157 : {
1158 0 : WPXString str;
1159 0 : appendCharacters(str, m_fonts[0],
1160 0 : m_encoding.get_value_or(UTF_16));
1161 0 : ret.insert("style:font-name", str);
1162 : }
1163 0 : switch (style.superSubType)
1164 : {
1165 : case SUPERSCRIPT:
1166 0 : ret.insert("style:text-position", "50% 67%");
1167 0 : break;
1168 : case SUBSCRIPT:
1169 0 : ret.insert("style:text-position", "-50% 67%");
1170 0 : break;
1171 : default:
1172 0 : break;
1173 : }
1174 0 : return ret;
1175 : }
1176 :
1177 0 : WPXString libmspub::MSPUBCollector::getColorString(const Color &color)
1178 : {
1179 0 : WPXString ret;
1180 0 : ret.sprintf("#%.2x%.2x%.2x",(unsigned char)color.r, (unsigned char)color.g, (unsigned char)color.b);
1181 : MSPUB_DEBUG_MSG(("String for r: 0x%x, g: 0x%x, b: 0x%x is %s\n", color.r, color.g, color.b, ret.cstr()));
1182 0 : return ret;
1183 : }
1184 :
1185 0 : void libmspub::MSPUBCollector::addBlackToPaletteIfNecessary()
1186 : {
1187 0 : if (m_paletteColors.size() < 8)
1188 : {
1189 0 : m_paletteColors.insert(m_paletteColors.begin(), Color());
1190 : }
1191 0 : }
1192 :
1193 0 : void libmspub::MSPUBCollector::assignShapesToPages()
1194 : {
1195 0 : for (unsigned i = 0; i < m_topLevelShapes.size(); ++i)
1196 : {
1197 0 : unsigned *ptr_pageSeqNum = getIfExists(m_pageSeqNumsByShapeSeqNum, m_topLevelShapes[i].getSeqNum());
1198 0 : m_topLevelShapes[i].setup(boost::bind(&libmspub::MSPUBCollector::setupShapeStructures, this, _1));
1199 0 : if (ptr_pageSeqNum)
1200 : {
1201 0 : PageInfo *ptr_page = getIfExists(m_pagesBySeqNum, *ptr_pageSeqNum);
1202 0 : if (ptr_page)
1203 : {
1204 0 : ptr_page->m_shapeGroupsOrdered.push_back(&m_topLevelShapes[i]);
1205 : }
1206 : }
1207 : }
1208 0 : }
1209 :
1210 0 : boost::optional<unsigned> libmspub::MSPUBCollector::getMasterPageSeqNum(unsigned pageSeqNum) const
1211 : {
1212 0 : boost::optional<unsigned> toReturn;
1213 0 : const unsigned *ptr_masterSeqNum = getIfExists_const(m_masterPagesByPageSeqNum, pageSeqNum);
1214 0 : if (ptr_masterSeqNum && m_masterPages.find(*ptr_masterSeqNum) != m_masterPages.end())
1215 : {
1216 0 : return *ptr_masterSeqNum;
1217 : }
1218 0 : return toReturn;
1219 : }
1220 :
1221 0 : void libmspub::MSPUBCollector::writePage(unsigned pageSeqNum) const
1222 : {
1223 0 : const PageInfo &pageInfo = m_pagesBySeqNum.find(pageSeqNum)->second;
1224 0 : WPXPropertyList pageProps;
1225 0 : if (m_widthSet)
1226 : {
1227 0 : pageProps.insert("svg:width", m_width);
1228 : }
1229 0 : if (m_heightSet)
1230 : {
1231 0 : pageProps.insert("svg:height", m_height);
1232 : }
1233 0 : const std::vector<ShapeGroupElement *> &shapeGroupsOrdered = pageInfo.m_shapeGroupsOrdered;
1234 0 : if (!shapeGroupsOrdered.empty())
1235 : {
1236 0 : m_painter->startGraphics(pageProps);
1237 0 : boost::optional<unsigned> masterSeqNum = getMasterPageSeqNum(pageSeqNum);
1238 0 : bool hasMaster = masterSeqNum.is_initialized();
1239 0 : if (hasMaster)
1240 : {
1241 0 : writePageBackground(masterSeqNum.get());
1242 : }
1243 0 : writePageBackground(pageSeqNum);
1244 0 : if (hasMaster)
1245 : {
1246 0 : writePageShapes(masterSeqNum.get());
1247 : }
1248 0 : writePageShapes(pageSeqNum);
1249 0 : m_painter->endGraphics();
1250 0 : }
1251 0 : }
1252 :
1253 0 : void libmspub::MSPUBCollector::writePageShapes(unsigned pageSeqNum) const
1254 : {
1255 0 : const PageInfo &pageInfo = m_pagesBySeqNum.find(pageSeqNum)->second;
1256 0 : const std::vector<ShapeGroupElement *> &shapeGroupsOrdered = pageInfo.m_shapeGroupsOrdered;
1257 0 : for (unsigned i = 0; i < shapeGroupsOrdered.size(); ++i)
1258 : {
1259 0 : ShapeGroupElement *shapeGroup = shapeGroupsOrdered[i];
1260 0 : shapeGroup->visit(boost::bind(&libmspub::MSPUBCollector::paintShape, this, _1, _2, _3, _4, _5));
1261 : }
1262 0 : }
1263 :
1264 0 : void libmspub::MSPUBCollector::writePageBackground(unsigned pageSeqNum) const
1265 : {
1266 0 : const unsigned *ptr_fillSeqNum = getIfExists_const(m_bgShapeSeqNumsByPageSeqNum, pageSeqNum);
1267 0 : if (ptr_fillSeqNum)
1268 : {
1269 0 : boost::shared_ptr<const Fill> ptr_fill;
1270 0 : const ShapeInfo *ptr_info = getIfExists_const(m_shapeInfosBySeqNum, *ptr_fillSeqNum);
1271 0 : if (ptr_info)
1272 : {
1273 0 : ptr_fill = ptr_info->m_fill;
1274 : }
1275 0 : if (ptr_fill)
1276 : {
1277 0 : ShapeInfo bg;
1278 0 : bg.m_type = RECTANGLE;
1279 0 : Coordinate wholePage(-m_width/2 * EMUS_IN_INCH, -m_height/2 * EMUS_IN_INCH, m_width/2 * EMUS_IN_INCH, m_height/2 * EMUS_IN_INCH);
1280 0 : bg.m_coordinates = wholePage;
1281 0 : bg.m_pageSeqNum = pageSeqNum;
1282 0 : bg.m_fill = ptr_fill;
1283 0 : paintShape(bg, Coordinate(), VectorTransformation2D(), false, VectorTransformation2D());
1284 0 : }
1285 : }
1286 0 : }
1287 :
1288 0 : bool libmspub::MSPUBCollector::pageIsMaster(unsigned pageSeqNum) const
1289 : {
1290 0 : return m_masterPages.find(pageSeqNum) != m_masterPages.end();
1291 : }
1292 :
1293 0 : bool libmspub::MSPUBCollector::go()
1294 : {
1295 0 : addBlackToPaletteIfNecessary();
1296 0 : assignShapesToPages();
1297 0 : if (m_pageSeqNumsOrdered.empty())
1298 : {
1299 0 : for (std::map<unsigned, PageInfo>::const_iterator i = m_pagesBySeqNum.begin();
1300 0 : i != m_pagesBySeqNum.end(); ++i)
1301 : {
1302 0 : if (!pageIsMaster(i->first))
1303 : {
1304 0 : writePage(i->first);
1305 : }
1306 : }
1307 : }
1308 : else
1309 : {
1310 0 : for (unsigned i = 0; i < m_pageSeqNumsOrdered.size(); ++i)
1311 : {
1312 : std::map<unsigned, PageInfo>::const_iterator iter =
1313 0 : m_pagesBySeqNum.find(m_pageSeqNumsOrdered[i]);
1314 0 : if (iter != m_pagesBySeqNum.end() && !pageIsMaster(iter->first))
1315 : {
1316 0 : writePage(iter->first);
1317 : }
1318 : }
1319 : }
1320 0 : return true;
1321 : }
1322 :
1323 :
1324 0 : bool libmspub::MSPUBCollector::addTextString(const std::vector<TextParagraph> &str, unsigned id)
1325 : {
1326 : MSPUB_DEBUG_MSG(("addTextString, id: 0x%x\n", id));
1327 0 : m_textStringsById[id] = str;
1328 0 : return true; //FIXME: Warn if the string already existed in the map.
1329 : }
1330 :
1331 0 : void libmspub::MSPUBCollector::setWidthInEmu(unsigned long widthInEmu)
1332 : {
1333 : //FIXME: Warn if this is called twice
1334 0 : m_width = ((double)widthInEmu) / EMUS_IN_INCH;
1335 0 : m_widthSet = true;
1336 0 : }
1337 :
1338 0 : void libmspub::MSPUBCollector::setHeightInEmu(unsigned long heightInEmu)
1339 : {
1340 : //FIXME: Warn if this is called twice
1341 0 : m_height = ((double)heightInEmu) / EMUS_IN_INCH;
1342 0 : m_heightSet = true;
1343 0 : }
1344 :
1345 0 : bool libmspub::MSPUBCollector::addImage(unsigned index, ImgType type, WPXBinaryData img)
1346 : {
1347 : MSPUB_DEBUG_MSG(("Image at index %d and of type 0x%x added.\n", index, type));
1348 0 : while (m_images.size() < index)
1349 : {
1350 0 : m_images.push_back(std::pair<ImgType, WPXBinaryData>(UNKNOWN, WPXBinaryData()));
1351 : }
1352 0 : m_images[index - 1] = std::pair<ImgType, WPXBinaryData>(type, img);
1353 0 : return true;
1354 : }
1355 :
1356 0 : WPXBinaryData *libmspub::MSPUBCollector::addBorderImage(ImgType type,
1357 : unsigned borderArtIndex)
1358 : {
1359 0 : while (borderArtIndex >= m_borderImages.size())
1360 : {
1361 0 : m_borderImages.push_back(BorderArtInfo());
1362 : }
1363 0 : m_borderImages[borderArtIndex].m_images.push_back(BorderImgInfo(type));
1364 0 : return &(m_borderImages[borderArtIndex].m_images.back().m_imgBlob);
1365 : }
1366 :
1367 0 : void libmspub::MSPUBCollector::setBorderImageOffset(unsigned index, unsigned offset)
1368 : {
1369 0 : while (index >= m_borderImages.size())
1370 : {
1371 0 : m_borderImages.push_back(BorderArtInfo());
1372 : }
1373 0 : BorderArtInfo &bai = m_borderImages[index];
1374 0 : bai.m_offsets.push_back(offset);
1375 0 : bool added = false;
1376 0 : for (std::vector<unsigned>::iterator i = bai.m_offsetsOrdered.begin();
1377 0 : i != bai.m_offsetsOrdered.end(); ++i)
1378 : {
1379 0 : if (*i >= offset)
1380 : {
1381 0 : bai.m_offsetsOrdered.insert(i, offset);
1382 0 : added = true;
1383 0 : break;
1384 : }
1385 : }
1386 0 : if (!added)
1387 : {
1388 0 : bai.m_offsetsOrdered.push_back(offset);
1389 : }
1390 0 : }
1391 :
1392 0 : void libmspub::MSPUBCollector::setShapePage(unsigned seqNum, unsigned pageSeqNum)
1393 : {
1394 0 : m_shapeInfosBySeqNum[seqNum].m_pageSeqNum = pageSeqNum;
1395 0 : m_pageSeqNumsByShapeSeqNum[seqNum] = pageSeqNum;
1396 0 : }
1397 :
1398 0 : void libmspub::MSPUBCollector::addTextColor(ColorReference c)
1399 : {
1400 0 : m_textColors.push_back(c);
1401 0 : }
1402 :
1403 0 : void libmspub::MSPUBCollector::designateMasterPage(unsigned seqNum)
1404 : {
1405 0 : m_masterPages.insert(seqNum);
1406 0 : }
1407 :
1408 0 : void libmspub::MSPUBCollector::setMasterPage(unsigned seqNum, unsigned masterPageSeqNum)
1409 : {
1410 0 : m_masterPagesByPageSeqNum[seqNum] = masterPageSeqNum;
1411 0 : }
1412 :
1413 : /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
|