1 /* 2 * Copyright (c) 2001-2015, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Stephan Aßmus <superstippi@gmx.de> 8 * Adrien Destugues <pulkomandy@pulkomandy.tk> 9 * Julian Harnath <julian.harnath@rwth-aachen.de> 10 */ 11 12 #ifndef SIMPLE_TRANSFORM_H 13 #define SIMPLE_TRANSFORM_H 14 15 #include <GradientLinear.h> 16 #include <GradientRadial.h> 17 #include <GradientRadialFocus.h> 18 #include <GradientDiamond.h> 19 #include <GradientConic.h> 20 #include <Point.h> 21 #include <Region.h> 22 23 #include "IntPoint.h" 24 #include "IntRect.h" 25 26 27 class SimpleTransform { 28 public: 29 SimpleTransform() 30 : 31 fScale(1.0) 32 { 33 } 34 35 void AddOffset(float x, float y) 36 { 37 fOffset.x += x; 38 fOffset.y += y; 39 } 40 41 void SetScale(float scale) 42 { 43 fScale = scale; 44 } 45 46 void Apply(BPoint* point) const 47 { 48 _Apply(point->x, point->y); 49 } 50 51 void Apply(IntPoint* point) const 52 { 53 _Apply(point->x, point->y); 54 } 55 56 void Apply(BRect* rect) const 57 { 58 if (fScale == 1.0) { 59 rect->OffsetBy(fOffset.x, fOffset.y); 60 } else { 61 _Apply(rect->left, rect->top); 62 _Apply(rect->right, rect->bottom); 63 } 64 } 65 66 void Apply(IntRect* rect) const 67 { 68 if (fScale == 1.0) { 69 rect->OffsetBy(fOffset.x, fOffset.y); 70 } else { 71 _Apply(rect->left, rect->top); 72 _Apply(rect->right, rect->bottom); 73 } 74 } 75 76 void Apply(BRegion* region) const 77 { 78 if (fScale == 1.0) { 79 region->OffsetBy(fOffset.x, fOffset.y); 80 } else { 81 // TODO: optimize some more 82 BRegion converted; 83 int32 count = region->CountRects(); 84 for (int32 i = 0; i < count; i++) { 85 BRect r = region->RectAt(i); 86 BPoint lt(r.LeftTop()); 87 BPoint rb(r.RightBottom()); 88 // offset to bottom right corner of pixel before transformation 89 rb.x++; 90 rb.y++; 91 // apply transformation 92 _Apply(lt.x, lt.y); 93 _Apply(rb.x, rb.y); 94 // reset bottom right to pixel "index" 95 rb.x--; 96 rb.y--; 97 // add rect to converted region 98 // NOTE/TODO: the rect would not have to go 99 // through the whole intersection test process, 100 // it is guaranteed not to overlap with any rect 101 // already contained in the region 102 converted.Include(BRect(lt, rb)); 103 } 104 *region = converted; 105 } 106 } 107 108 void Apply(BGradient* gradient) const 109 { 110 switch (gradient->GetType()) { 111 case BGradient::TYPE_LINEAR: 112 { 113 BGradientLinear* linear = (BGradientLinear*) gradient; 114 BPoint start = linear->Start(); 115 BPoint end = linear->End(); 116 Apply(&start); 117 Apply(&end); 118 linear->SetStart(start); 119 linear->SetEnd(end); 120 break; 121 } 122 123 case BGradient::TYPE_RADIAL: 124 { 125 BGradientRadial* radial = (BGradientRadial*) gradient; 126 BPoint center = radial->Center(); 127 Apply(¢er); 128 radial->SetCenter(center); 129 break; 130 } 131 132 case BGradient::TYPE_RADIAL_FOCUS: 133 { 134 BGradientRadialFocus* radialFocus = 135 (BGradientRadialFocus*)gradient; 136 BPoint center = radialFocus->Center(); 137 BPoint focal = radialFocus->Focal(); 138 Apply(¢er); 139 Apply(&focal); 140 radialFocus->SetCenter(center); 141 radialFocus->SetFocal(focal); 142 break; 143 } 144 145 case BGradient::TYPE_DIAMOND: 146 { 147 BGradientDiamond* diamond = (BGradientDiamond*) gradient; 148 BPoint center = diamond->Center(); 149 Apply(¢er); 150 diamond->SetCenter(center); 151 break; 152 } 153 154 case BGradient::TYPE_CONIC: 155 { 156 BGradientConic* conic = (BGradientConic*) gradient; 157 BPoint center = conic->Center(); 158 Apply(¢er); 159 conic->SetCenter(center); 160 break; 161 } 162 163 case BGradient::TYPE_NONE: 164 { 165 break; 166 } 167 } 168 169 // Make sure the gradient is fully padded so that out of bounds access 170 // get the correct colors 171 gradient->SortColorStopsByOffset(); 172 173 BGradient::ColorStop* end = gradient->ColorStopAtFast( 174 gradient->CountColorStops() - 1); 175 176 if (end->offset != 255) 177 gradient->AddColor(end->color, 255); 178 179 BGradient::ColorStop* start = gradient->ColorStopAtFast(0); 180 181 if (start->offset != 0) 182 gradient->AddColor(start->color, 0); 183 184 gradient->SortColorStopsByOffset(); 185 } 186 187 void Apply(BPoint* destination, const BPoint* source, int32 count) const 188 { 189 // TODO: optimize this, it should be smarter 190 while (count--) { 191 *destination = *source; 192 Apply(destination); 193 source++; 194 destination++; 195 } 196 } 197 198 void Apply(BRect* destination, const BRect* source, int32 count) const 199 { 200 // TODO: optimize this, it should be smarter 201 while (count--) { 202 *destination = *source; 203 Apply(destination); 204 source++; 205 destination++; 206 } 207 } 208 209 void Apply(BRegion* destination, const BRegion* source, int32 count) const 210 { 211 // TODO: optimize this, it should be smarter 212 while (count--) { 213 *destination = *source; 214 Apply(destination); 215 source++; 216 destination++; 217 } 218 } 219 220 private: 221 void _Apply(int32& x, int32& y) const 222 { 223 x *= (int32)fScale; 224 y *= (int32)fScale; 225 x += (int32)fOffset.x; 226 y += (int32)fOffset.y; 227 } 228 229 void _Apply(float& x, float& y) const 230 { 231 x *= fScale; 232 y *= fScale; 233 x += fOffset.x; 234 y += fOffset.y; 235 } 236 237 private: 238 BPoint fOffset; 239 float fScale; 240 }; 241 242 243 #endif // SIMPLE_TRANSFORM_H 244