/* * Copyright (c) 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: * Axel Dörfler, axeld@pinc-software.de * Stephan Aßmus * Adrien Destugues * Julian Harnath */ #ifndef SIMPLE_TRANSFORM_H #define SIMPLE_TRANSFORM_H #include #include #include #include #include #include #include #include "IntPoint.h" #include "IntRect.h" class SimpleTransform { public: SimpleTransform() : fScale(1.0) { } void AddOffset(float x, float y) { fOffset.x += x; fOffset.y += y; } void SetScale(float scale) { fScale = scale; } void Apply(BPoint* point) const { _Apply(point->x, point->y); } void Apply(IntPoint* point) const { _Apply(point->x, point->y); } void Apply(BRect* rect) const { if (fScale == 1.0) { rect->OffsetBy(fOffset.x, fOffset.y); } else { _Apply(rect->left, rect->top); _Apply(rect->right, rect->bottom); } } void Apply(IntRect* rect) const { if (fScale == 1.0) { rect->OffsetBy(fOffset.x, fOffset.y); } else { _Apply(rect->left, rect->top); _Apply(rect->right, rect->bottom); } } void Apply(BRegion* region) const { if (fScale == 1.0) { region->OffsetBy(fOffset.x, fOffset.y); } else { // TODO: optimize some more BRegion converted; int32 count = region->CountRects(); for (int32 i = 0; i < count; i++) { BRect r = region->RectAt(i); BPoint lt(r.LeftTop()); BPoint rb(r.RightBottom()); // offset to bottom right corner of pixel before transformation rb.x++; rb.y++; // apply transformation _Apply(lt.x, lt.y); _Apply(rb.x, rb.y); // reset bottom right to pixel "index" rb.x--; rb.y--; // add rect to converted region // NOTE/TODO: the rect would not have to go // through the whole intersection test process, // it is guaranteed not to overlap with any rect // already contained in the region converted.Include(BRect(lt, rb)); } *region = converted; } } void Apply(BGradient* gradient) const { switch (gradient->GetType()) { case BGradient::TYPE_LINEAR: { BGradientLinear* linear = (BGradientLinear*) gradient; BPoint start = linear->Start(); BPoint end = linear->End(); Apply(&start); Apply(&end); linear->SetStart(start); linear->SetEnd(end); break; } case BGradient::TYPE_RADIAL: { BGradientRadial* radial = (BGradientRadial*) gradient; BPoint center = radial->Center(); Apply(¢er); radial->SetCenter(center); break; } case BGradient::TYPE_RADIAL_FOCUS: { BGradientRadialFocus* radialFocus = (BGradientRadialFocus*)gradient; BPoint center = radialFocus->Center(); BPoint focal = radialFocus->Focal(); Apply(¢er); Apply(&focal); radialFocus->SetCenter(center); radialFocus->SetFocal(focal); break; } case BGradient::TYPE_DIAMOND: { BGradientDiamond* diamond = (BGradientDiamond*) gradient; BPoint center = diamond->Center(); Apply(¢er); diamond->SetCenter(center); break; } case BGradient::TYPE_CONIC: { BGradientConic* conic = (BGradientConic*) gradient; BPoint center = conic->Center(); Apply(¢er); conic->SetCenter(center); break; } case BGradient::TYPE_NONE: { break; } } // Make sure the gradient is fully padded so that out of bounds access // get the correct colors gradient->SortColorStopsByOffset(); BGradient::ColorStop* end = gradient->ColorStopAtFast( gradient->CountColorStops() - 1); if (end->offset != 255) gradient->AddColor(end->color, 255); BGradient::ColorStop* start = gradient->ColorStopAtFast(0); if (start->offset != 0) gradient->AddColor(start->color, 0); gradient->SortColorStopsByOffset(); } void Apply(BPoint* destination, const BPoint* source, int32 count) const { // TODO: optimize this, it should be smarter while (count--) { *destination = *source; Apply(destination); source++; destination++; } } void Apply(BRect* destination, const BRect* source, int32 count) const { // TODO: optimize this, it should be smarter while (count--) { *destination = *source; Apply(destination); source++; destination++; } } void Apply(BRegion* destination, const BRegion* source, int32 count) const { // TODO: optimize this, it should be smarter while (count--) { *destination = *source; Apply(destination); source++; destination++; } } private: void _Apply(int32& x, int32& y) const { x *= (int32)fScale; y *= (int32)fScale; x += (int32)fOffset.x; y += (int32)fOffset.y; } void _Apply(float& x, float& y) const { x *= fScale; y *= fScale; x += fOffset.x; y += fOffset.y; } private: BPoint fOffset; float fScale; }; #endif // SIMPLE_TRANSFORM_H