1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ 2 3 /* libmwaw 4 * Version: MPL 2.0 / LGPLv2+ 5 * 6 * The contents of this file are subject to the Mozilla Public License Version 7 * 2.0 (the "License"); you may not use this file except in compliance with 8 * the License or as specified alternatively below. You may obtain a copy of 9 * the License at http://www.mozilla.org/MPL/ 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 * 16 * Major Contributor(s): 17 * Copyright (C) 2002 William Lachance (wrlach@gmail.com) 18 * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) 19 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) 20 * Copyright (C) 2006, 2007 Andrew Ziem 21 * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) 22 * 23 * 24 * All Rights Reserved. 25 * 26 * For minor contributions see the git repository. 27 * 28 * Alternatively, the contents of this file may be used under the terms of 29 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), 30 * in which case the provisions of the LGPLv2+ are applicable 31 * instead of those above. 32 */ 33 #ifndef MWAW_GRAPHIC_STYLE 34 # define MWAW_GRAPHIC_STYLE 35 # include <ostream> 36 # include <string> 37 # include <vector> 38 39 # include "librevenge/librevenge.h" 40 # include "libmwaw_internal.hxx" 41 42 /** a structure used to define a picture style 43 44 \note in order to define the internal surface style, first it looks for 45 a gradient, if so it uses it. Then it looks for a pattern. Finally if 46 it found nothing, it uses surfaceColor and surfaceOpacity.*/ 47 class MWAWGraphicStyle 48 { 49 public: 50 //! an enum used to define the basic line cap 51 enum LineCap { C_Butt, C_Square, C_Round }; 52 //! an enum used to define the basic line join 53 enum LineJoin { J_Miter, J_Round, J_Bevel }; 54 55 //! a structure used to define an arrow 56 struct Arrow { 57 //! constructor ( no arrow) ArrowMWAWGraphicStyle::Arrow58 Arrow() 59 : m_viewBox() 60 , m_path("") 61 , m_width(0) 62 , m_isCentered(false) 63 { 64 } 65 //! constructor ArrowMWAWGraphicStyle::Arrow66 Arrow(float w, MWAWBox2i const &box, std::string const &path, bool centered=false) 67 : m_viewBox(box) 68 , m_path(path) 69 , m_width(w) 70 , m_isCentered(centered) 71 { 72 } 73 //! returns a basic plain arrow plainMWAWGraphicStyle::Arrow74 static Arrow plain() 75 { 76 return Arrow(5, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(20,30)), "m10 0-10 30h20z", false); 77 } 78 //! operator<< operator <<(std::ostream & o,Arrow const & arrow)79 friend std::ostream &operator<<(std::ostream &o, Arrow const &arrow) 80 { 81 if (arrow.isEmpty()) return o; 82 o << "w=" << arrow.m_width << ","; 83 o << "viewbox=" << arrow.m_viewBox << ","; 84 o << "path=" << arrow.m_path << ","; 85 if (arrow.m_isCentered) o << "centered,"; 86 return o; 87 } 88 //! operator== operator ==MWAWGraphicStyle::Arrow89 bool operator==(Arrow const &arrow) const 90 { 91 return m_width>=arrow.m_width && m_width<=arrow.m_width && 92 m_viewBox==arrow.m_viewBox && m_path==arrow.m_path && m_isCentered==arrow.m_isCentered; 93 } 94 //! operator!= operator !=MWAWGraphicStyle::Arrow95 bool operator!=(Arrow const &arrow) const 96 { 97 return !(*this==arrow); 98 } 99 //! operator< operator <MWAWGraphicStyle::Arrow100 bool operator<(Arrow const &arrow) const 101 { 102 if (m_isCentered<arrow.m_isCentered) return m_isCentered ? true : false; 103 return m_width<arrow.m_width && m_viewBox<arrow.m_viewBox && m_path < arrow.m_path; 104 } 105 //! operator<= operator <=MWAWGraphicStyle::Arrow106 bool operator<=(Arrow const &arrow) const 107 { 108 return *this<arrow || *this==arrow; 109 } 110 //! operator> operator >MWAWGraphicStyle::Arrow111 bool operator>(Arrow const &arrow) const 112 { 113 return !(*this<=arrow); 114 } 115 //! operator>= operator >=MWAWGraphicStyle::Arrow116 bool operator>=(Arrow const &arrow) const 117 { 118 return !(*this<arrow); 119 } 120 //! returns true if there is no arrow isEmptyMWAWGraphicStyle::Arrow121 bool isEmpty() const 122 { 123 return m_width<=0 || m_path.empty(); 124 } 125 //! add a arrow to the propList knowing the type (start, end) 126 void addTo(librevenge::RVNGPropertyList &propList, std::string const &type) const; 127 128 //! the arrow viewbox 129 MWAWBox2i m_viewBox; 130 //! the arrow path 131 std::string m_path; 132 //! the arrow width in point 133 float m_width; 134 //! flag to know if the arrow is centered 135 bool m_isCentered; 136 }; 137 138 /** a basic gradient used in a MWAWGraphicStyle */ 139 struct Gradient { 140 //! a structure used to define the gradient limit in MWAWGraphicStyle 141 struct Stop { 142 //! constructor StopMWAWGraphicStyle::Gradient::Stop143 explicit Stop(float offset=0.0, MWAWColor const &col=MWAWColor::black(), float opacity=1.0) 144 : m_offset(offset) 145 , m_color(col) 146 , m_opacity(opacity) 147 { 148 } 149 /** compare two gradient */ cmpMWAWGraphicStyle::Gradient::Stop150 int cmp(Stop const &a) const 151 { 152 if (m_offset < a.m_offset) return -1; 153 if (m_offset > a.m_offset) return 1; 154 if (m_color < a.m_color) return -1; 155 if (m_color > a.m_color) return 1; 156 if (m_opacity < a.m_opacity) return -1; 157 if (m_opacity > a.m_opacity) return 1; 158 return 0; 159 } 160 //! a print operator operator <<MWAWGraphicStyle::Gradient161 friend std::ostream &operator<<(std::ostream &o, Stop const &st) 162 { 163 o << "offset=" << st.m_offset << ","; 164 o << "color=" << st.m_color << ","; 165 if (st.m_opacity<1) 166 o << "opacity=" << st.m_opacity*100.f << "%,"; 167 return o; 168 } 169 //! the offset 170 float m_offset; 171 //! the color 172 MWAWColor m_color; 173 //! the opacity 174 float m_opacity; 175 }; 176 //! an enum used to define the gradient type 177 enum Type { G_None, G_Axial, G_Linear, G_Radial, G_Rectangular, G_Square, G_Ellipsoid }; 178 //! constructor GradientMWAWGraphicStyle::Gradient179 Gradient() 180 : m_type(G_None) 181 , m_stopList() 182 , m_angle(0) 183 , m_border(0) 184 , m_percentCenter(0.5f,0.5f) 185 , m_radius(1) 186 { 187 m_stopList.push_back(Stop(0.0, MWAWColor::white())); 188 m_stopList.push_back(Stop(1.0, MWAWColor::black())); 189 } 190 //! returns true if the gradient is defined hasGradientMWAWGraphicStyle::Gradient191 bool hasGradient(bool complex=false) const 192 { 193 return m_type != G_None && static_cast<int>(m_stopList.size()) >= (complex ? 3 : 2); 194 } 195 //! add a gradient to the propList 196 void addTo(librevenge::RVNGPropertyList &propList) const; 197 /** returns the average gradient color if the gradient is defined. */ 198 bool getAverageColor(MWAWColor &color) const; 199 //! a print operator operator <<(std::ostream & o,Gradient const & grad)200 friend std::ostream &operator<<(std::ostream &o, Gradient const &grad) 201 { 202 switch (grad.m_type) { 203 case Gradient::G_Axial: 204 o << "axial,"; 205 break; 206 case Gradient::G_Linear: 207 o << "linear,"; 208 break; 209 case Gradient::G_Radial: 210 o << "radial,"; 211 break; 212 case Gradient::G_Rectangular: 213 o << "rectangular,"; 214 break; 215 case Gradient::G_Square: 216 o << "square,"; 217 break; 218 case Gradient::G_Ellipsoid: 219 o << "ellipsoid,"; 220 break; 221 case Gradient::G_None: 222 #if !defined(__clang__) 223 default: 224 #endif 225 break; 226 } 227 if (grad.m_angle>0 || grad.m_angle<0) o << "angle=" << grad.m_angle << ","; 228 if (grad.m_stopList.size() >= 2) { 229 o << "stops=["; 230 for (auto const &stop : grad.m_stopList) 231 o << "[" << stop << "],"; 232 o << "],"; 233 } 234 if (grad.m_border>0) o << "border=" << grad.m_border*100 << "%,"; 235 if (grad.m_percentCenter != MWAWVec2f(0.5f,0.5f)) o << "center=" << grad.m_percentCenter << ","; 236 if (grad.m_radius<1) o << "radius=" << grad.m_radius << ","; 237 return o; 238 } 239 240 /** compare two gradient */ cmpMWAWGraphicStyle::Gradient241 int cmp(Gradient const &a) const 242 { 243 if (m_type < a.m_type) return -1; 244 if (m_type > a.m_type) return 1; 245 if (m_angle < a.m_angle) return -1; 246 if (m_angle > a.m_angle) return 1; 247 if (m_stopList.size() < a.m_stopList.size()) return 1; 248 if (m_stopList.size() > a.m_stopList.size()) return -1; 249 for (auto c :m_stopList) { 250 int diff = c.cmp(c); 251 if (diff) return diff; 252 } 253 if (m_border < a.m_border) return -1; 254 if (m_border > a.m_border) return 1; 255 int diff=m_percentCenter.cmp(a.m_percentCenter); 256 if (diff) return diff; 257 if (m_radius < a.m_radius) return -1; 258 if (m_radius > a.m_radius) return 1; 259 return 0; 260 } 261 //! the gradient type 262 Type m_type; 263 //! the list of gradient limits 264 std::vector<Stop> m_stopList; 265 //! the gradient angle 266 float m_angle; 267 //! the gradient border opacity 268 float m_border; 269 //! the gradient center 270 MWAWVec2f m_percentCenter; 271 //! the gradient radius 272 float m_radius; 273 }; 274 275 /** a basic hatch used in MWAWGraphicStyle */ 276 struct Hatch { 277 //! the potential type 278 enum Type { H_None, H_Single, H_Double, H_Triple }; 279 //! constructor HatchMWAWGraphicStyle::Hatch280 Hatch() 281 : m_type(H_None) 282 , m_color(MWAWColor::black()) 283 , m_distance(1.f/72) 284 , m_rotation(0) 285 { 286 } 287 //! returns true if the gradient is defined hasHatchMWAWGraphicStyle::Hatch288 bool hasHatch() const 289 { 290 return m_type != H_None && m_distance>0; 291 } 292 //! add a hatch to the propList 293 void addTo(librevenge::RVNGPropertyList &propList) const; 294 //! a print operator operator <<(std::ostream & o,Hatch const & hatch)295 friend std::ostream &operator<<(std::ostream &o, Hatch const &hatch) 296 { 297 if (hatch.m_type==H_None || hatch.m_distance<=0) 298 return o; 299 switch (hatch.m_type) { 300 case Hatch::H_None: 301 break; 302 case Hatch::H_Single: 303 o << "single,"; 304 break; 305 case Hatch::H_Double: 306 o << "double,"; 307 break; 308 case Hatch::H_Triple: 309 o << "triple,"; 310 break; 311 default: 312 o << "###type=" << int(hatch.m_type) << ","; 313 break; 314 } 315 if (!hatch.m_color.isBlack()) 316 o << hatch.m_color << ","; 317 o << "dist=" << 72*hatch.m_distance << "pt,"; 318 if (hatch.m_rotation>0 || hatch.m_rotation<0) 319 o << "rot=" << hatch.m_rotation << "deg,"; 320 return o; 321 } 322 /** compare two hatchs */ cmpMWAWGraphicStyle::Hatch323 int cmp(Hatch const &a) const 324 { 325 if (m_type < a.m_type) return -1; 326 if (m_type > a.m_type) return 1; 327 if (m_color < a.m_color) return -1; 328 if (m_color > a.m_color) return 1; 329 if (m_distance < a.m_distance) return -1; 330 if (m_distance > a.m_distance) return 1; 331 if (m_rotation < a.m_rotation) return -1; 332 if (m_rotation > a.m_rotation) return 1; 333 return 0; 334 } 335 //! the hatch type 336 Type m_type; 337 //! the hatch color 338 MWAWColor m_color; 339 //! the hatch distance in inches 340 float m_distance; 341 //! the rotation (in degrees) 342 float m_rotation; 343 }; 344 /** a basic pattern used in a MWAWGraphicStyle: 345 - either given a list of 8x8, 16x16, 32x32 bytes with two colors 346 - or with a picture ( and an average color) 347 */ 348 struct Pattern { 349 //! constructor PatternMWAWGraphicStyle::Pattern350 Pattern() 351 : m_dim(0,0) 352 , m_data() 353 , m_picture() 354 , m_pictureAverageColor(MWAWColor::white()) 355 { 356 m_colors[0]=MWAWColor::black(); 357 m_colors[1]=MWAWColor::white(); 358 } 359 //! constructor from a binary data PatternMWAWGraphicStyle::Pattern360 Pattern(MWAWVec2i dim, MWAWEmbeddedObject const &picture, MWAWColor const &avColor) 361 : m_dim(dim) 362 , m_data() 363 , m_picture(picture) 364 , m_pictureAverageColor(avColor) 365 { 366 m_colors[0]=MWAWColor::black(); 367 m_colors[1]=MWAWColor::white(); 368 } 369 Pattern(Pattern const &)=default; 370 Pattern &operator=(Pattern const &)=default; 371 Pattern &operator=(Pattern &&)=default; 372 //! virtual destructor 373 virtual ~Pattern(); 374 //! return true if we does not have a pattern emptyMWAWGraphicStyle::Pattern375 bool empty() const 376 { 377 if (m_dim[0]==0 || m_dim[1]==0) return true; 378 if (!m_picture.m_dataList.empty()) return false; 379 if (m_dim[0]!=8 && m_dim[0]!=16 && m_dim[0]!=32) return true; 380 return m_data.size()!=size_t((m_dim[0]/8)*m_dim[1]); 381 } 382 //! return the average color 383 bool getAverageColor(MWAWColor &col) const; 384 //! check if the pattern has only one color; if so returns true... 385 bool getUniqueColor(MWAWColor &col) const; 386 /** tries to convert the picture in a binary data ( ppm) */ 387 bool getBinary(MWAWEmbeddedObject &picture) const; 388 389 /** compare two patterns */ cmpMWAWGraphicStyle::Pattern390 int cmp(Pattern const &a) const 391 { 392 int diff = m_dim.cmp(a.m_dim); 393 if (diff) return diff; 394 if (m_data.size() < a.m_data.size()) return -1; 395 if (m_data.size() > a.m_data.size()) return 1; 396 for (size_t h=0; h < m_data.size(); ++h) { 397 if (m_data[h]<a.m_data[h]) return 1; 398 if (m_data[h]>a.m_data[h]) return -1; 399 } 400 for (int i=0; i<2; ++i) { 401 if (m_colors[i] < a.m_colors[i]) return 1; 402 if (m_colors[i] > a.m_colors[i]) return -1; 403 } 404 if (m_pictureAverageColor < a.m_pictureAverageColor) return 1; 405 if (m_pictureAverageColor > a.m_pictureAverageColor) return -1; 406 diff=m_picture.cmp(a.m_picture); 407 if (diff) return diff; 408 return 0; 409 } 410 //! a print operator operator <<(std::ostream & o,Pattern const & pat)411 friend std::ostream &operator<<(std::ostream &o, Pattern const &pat) 412 { 413 o << "dim=" << pat.m_dim << ","; 414 if (!pat.m_picture.isEmpty()) { 415 o << "pict=" << pat.m_picture << ","; 416 o << "col[average]=" << pat.m_pictureAverageColor << ","; 417 } 418 else { 419 if (!pat.m_colors[0].isBlack()) o << "col0=" << pat.m_colors[0] << ","; 420 if (!pat.m_colors[1].isWhite()) o << "col1=" << pat.m_colors[1] << ","; 421 o << "["; 422 for (auto data : pat.m_data) 423 o << std::hex << static_cast<int>(data) << std::dec << ","; 424 o << "],"; 425 } 426 return o; 427 } 428 //! the dimension width x height 429 MWAWVec2i m_dim; 430 431 //! the two indexed colors 432 MWAWColor m_colors[2]; 433 //! the pattern data: a sequence of data: p[0..7,0],p[8..15,0]...p[0..7,1],p[8..15,1], ... 434 std::vector<unsigned char> m_data; 435 protected: 436 //! a picture 437 MWAWEmbeddedObject m_picture; 438 //! the picture average color 439 MWAWColor m_pictureAverageColor; 440 }; 441 //! constructor MWAWGraphicStyle()442 MWAWGraphicStyle() 443 : m_lineDashWidth() 444 , m_lineWidth(1) 445 , m_lineCap(C_Butt) 446 , m_lineJoin(J_Miter) 447 , m_lineOpacity(1) 448 , m_lineColor(MWAWColor::black()) 449 , m_surfaceColor(MWAWColor::white()) 450 , m_surfaceOpacity(0) 451 , m_shadowColor(MWAWColor::black()) 452 , m_shadowOpacity(0) 453 , m_shadowOffset(1,1) 454 , m_pattern() 455 , m_gradient() 456 , m_hatch() 457 , m_backgroundColor(MWAWColor::white()) 458 , m_backgroundOpacity(-1) 459 , m_rotate(0) 460 , m_bordersList() 461 , m_frameName("") 462 , m_frameNextName("") 463 , m_fillRuleEvenOdd(false) 464 , m_doNotPrint(false) 465 , m_extra("") 466 { 467 for (auto &fl : m_flip) fl=false; 468 } 469 MWAWGraphicStyle(MWAWGraphicStyle const &)=default; 470 MWAWGraphicStyle &operator=(MWAWGraphicStyle const &)=default; 471 MWAWGraphicStyle &operator=(MWAWGraphicStyle &&)=default; 472 /** returns an empty style. Can be used to initialize a default frame style...*/ emptyStyle()473 static MWAWGraphicStyle emptyStyle() 474 { 475 MWAWGraphicStyle res; 476 res.m_lineWidth=0; 477 return res; 478 } 479 //! virtual destructor 480 virtual ~MWAWGraphicStyle(); 481 //! returns true if the border is defined hasLine() const482 bool hasLine() const 483 { 484 return m_lineWidth>0 && m_lineOpacity>0; 485 } 486 //! set the surface color setSurfaceColor(MWAWColor const & col,float opacity=1)487 void setSurfaceColor(MWAWColor const &col, float opacity = 1) 488 { 489 m_surfaceColor = col; 490 m_surfaceOpacity = opacity; 491 } 492 //! returns true if the surface is defined hasSurfaceColor() const493 bool hasSurfaceColor() const 494 { 495 return m_surfaceOpacity > 0; 496 } 497 //! set the pattern setPattern(Pattern const & pat,float opacity=1)498 void setPattern(Pattern const &pat, float opacity = 1) 499 { 500 m_pattern=pat; 501 m_surfaceOpacity = opacity; 502 } 503 //! returns true if the pattern is defined hasPattern() const504 bool hasPattern() const 505 { 506 return !m_pattern.empty() && m_surfaceOpacity > 0; 507 } 508 //! returns true if the gradient is defined hasGradient(bool complex=false) const509 bool hasGradient(bool complex=false) const 510 { 511 return m_gradient.hasGradient(complex); 512 } 513 //! returns true if the hatch is defined hasHatch() const514 bool hasHatch() const 515 { 516 return m_hatch.hasHatch(); 517 } 518 //! returns true if the interior surface is defined hasSurface() const519 bool hasSurface() const 520 { 521 return hasSurfaceColor() || hasPattern() || hasGradient() || hasHatch(); 522 } 523 //! set the background color setBackgroundColor(MWAWColor const & col,float opacity=1)524 void setBackgroundColor(MWAWColor const &col, float opacity = 1) 525 { 526 m_backgroundColor = col; 527 m_backgroundOpacity = opacity; 528 } 529 //! returns true if the background is defined hasBackgroundColor() const530 bool hasBackgroundColor() const 531 { 532 return m_backgroundOpacity > 0; 533 } 534 //! set the shadow color setShadowColor(MWAWColor const & col,float opacity=1)535 void setShadowColor(MWAWColor const &col, float opacity = 1) 536 { 537 m_shadowColor = col; 538 m_shadowOpacity = opacity; 539 } 540 //! returns true if the shadow is defined hasShadow() const541 bool hasShadow() const 542 { 543 return m_shadowOpacity > 0; 544 } 545 //! return true if the frame has some border hasBorders() const546 bool hasBorders() const 547 { 548 return !m_bordersList.empty(); 549 } 550 //! return true if the frame has some border hasSameBorders() const551 bool hasSameBorders() const 552 { 553 if (m_bordersList.empty()) return true; 554 if (m_bordersList.size()!=4) return false; 555 for (size_t i=1; i<m_bordersList.size(); ++i) { 556 if (m_bordersList[i]!=m_bordersList[0]) 557 return false; 558 } 559 return true; 560 } 561 //! return the frame border: libmwaw::Left | ... borders() const562 std::vector<MWAWBorder> const &borders() const 563 { 564 return m_bordersList; 565 } 566 //! reset the border resetBorders()567 void resetBorders() 568 { 569 m_bordersList.resize(0); 570 } 571 //! sets the cell border: wh=libmwaw::LeftBit|... 572 void setBorders(int wh, MWAWBorder const &border); 573 //! a print operator 574 friend std::ostream &operator<<(std::ostream &o, MWAWGraphicStyle const &st); 575 //! add all the parameters to the propList excepted the frame parameter: the background and the borders 576 void addTo(librevenge::RVNGPropertyList &pList, bool only1d=false) const; 577 //! add all the frame parameters to propList: the background and the borders 578 void addFrameTo(librevenge::RVNGPropertyList &pList) const; 579 /** compare two styles */ 580 int cmp(MWAWGraphicStyle const &a) const; 581 582 //! the dash array: a sequence of (fullsize, emptysize) 583 std::vector<float> m_lineDashWidth; 584 //! the linewidth 585 float m_lineWidth; 586 //! the line cap 587 LineCap m_lineCap; 588 //! the line join 589 LineJoin m_lineJoin; 590 //! the line opacity: 0=transparent 591 float m_lineOpacity; 592 //! the line color 593 MWAWColor m_lineColor; 594 //! the surface color 595 MWAWColor m_surfaceColor; 596 //! true if the surface has some color 597 float m_surfaceOpacity; 598 599 //! the shadow color 600 MWAWColor m_shadowColor; 601 //! true if the shadow has some color 602 float m_shadowOpacity; 603 //! the shadow offset 604 MWAWVec2f m_shadowOffset; 605 606 //! the pattern if it exists 607 Pattern m_pattern; 608 609 //! the gradient 610 Gradient m_gradient; 611 //! the hatch 612 Hatch m_hatch; 613 614 // 615 // related to the frame 616 // 617 618 //! the background color 619 MWAWColor m_backgroundColor; 620 //! true if the background has some color 621 float m_backgroundOpacity; 622 //! the rotation 623 float m_rotate; 624 //! the borders MWAWBorder::Pos (for a frame) 625 std::vector<MWAWBorder> m_bordersList; 626 //! the frame name 627 std::string m_frameName; 628 //! the frame next name (if there is a link) 629 std::string m_frameNextName; 630 631 //! the two arrows corresponding to start and end extremity 632 Arrow m_arrows[2]; 633 634 // 635 // some transformation: must probably be somewhere else 636 // 637 638 //! two bool to indicated we need to flip the shape or not 639 bool m_flip[2]; 640 641 //! true if the fill rule is evenod 642 bool m_fillRuleEvenOdd; 643 644 //! a bool to know if the shape must not be printed 645 bool m_doNotPrint; 646 //! extra data 647 std::string m_extra; 648 }; 649 #endif 650 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: 651