/* * Copyright 2014 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "harness.h" static const char* kAppSignature = "application/x-vnd.Haiku-Transformation"; class BitmapTest : public Test { public: BitmapTest(const char* name) : Test(name), fBitmap(_LoadBitmap(555)) { } private: status_t _GetAppResources(BResources& resources) const { app_info info; status_t status = be_app->GetAppInfo(&info); if (status != B_OK) return status; return resources.SetTo(&info.ref); } BBitmap* _LoadBitmap(int resourceID) const { BResources resources; status_t status = _GetAppResources(resources); if (status != B_OK) return NULL; size_t dataSize; const void* data = resources.LoadResource(B_MESSAGE_TYPE, resourceID, &dataSize); if (data == NULL) return NULL; BMemoryIO stream(data, dataSize); // Try to read as an archived bitmap. BMessage archive; status = archive.Unflatten(&stream); if (status != B_OK) return NULL; BBitmap* bitmap = new BBitmap(&archive); status = bitmap->InitCheck(); if (status != B_OK) { delete bitmap; bitmap = NULL; } return bitmap; } protected: BBitmap* fBitmap; }; // #pragma mark - Test1 class RectsTest : public Test { public: RectsTest() : Test("Rects") { } virtual void Draw(BView* view, BRect updateRect) { view->DrawString("Rects", BPoint(20, 30)); view->SetDrawingMode(B_OP_ALPHA); view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); BRect rect(view->Bounds()); rect.OffsetTo(B_ORIGIN); rect.InsetBy(rect.Width() / 3, rect.Height() / 3); BPoint center( rect.left + rect.Width() / 2, rect.top + rect.Height() / 2); for (int32 i = 0; i < 360; i += 40) { BAffineTransform transform; transform.RotateBy(center, i * M_PI / 180.0); view->SetTransform(transform); view->SetHighColor(51, 151, 255, 20); view->FillRect(rect); view->SetHighColor(51, 255, 151, 180); view->DrawString("Rect", center); } } }; // #pragma mark - AlphaMaskBitmapTest class AlphaMaskBitmapTest : public BitmapTest { public: AlphaMaskBitmapTest() : BitmapTest("Alpha Masked Bitmap") { } virtual void Draw(BView* view, BRect updateRect) { BRect rect(view->Bounds()); if (fBitmap == NULL) { view->SetHighColor(255, 0, 0); view->FillRect(rect); view->SetHighColor(0, 0, 0); view->DrawString("Failed to load the bitmap.", BPoint(20, 20)); return; } rect.left = (rect.Width() - fBitmap->Bounds().Width()) / 2; rect.top = (rect.Height() - fBitmap->Bounds().Height()) / 2; rect.right = rect.left + fBitmap->Bounds().Width(); rect.bottom = rect.top + fBitmap->Bounds().Height(); BPoint center( rect.left + rect.Width() / 2, rect.top + rect.Height() / 2); BPicture picture; view->BeginPicture(&picture); view->SetDrawingMode(B_OP_ALPHA); view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); BFont font; view->GetFont(&font); font.SetSize(70); view->SetFont(&font); view->SetHighColor(0, 0, 0, 80); view->FillRect(view->Bounds()); view->SetHighColor(0, 0, 0, 255); view->DrawString("CLIPPING", BPoint(0, center.y + 35)); view->EndPicture(); view->ClipToPicture(&picture); BAffineTransform transform; transform.RotateBy(center, 30 * M_PI / 180.0); view->SetTransform(transform); view->DrawBitmap(fBitmap, fBitmap->Bounds(), rect); } }; // #pragma mark - Gradient class GradientTest : public Test { public: GradientTest() : Test("Gradient") { } virtual void Draw(BView* view, BRect updateRect) { BRect rect(view->Bounds()); rect.InsetBy(rect.Width() / 3, rect.Height() / 3); BPoint center( rect.left + rect.Width() / 2, rect.top + rect.Height() / 2); BAffineTransform transform; transform.RotateBy(center, 30.0 * M_PI / 180.0); view->SetTransform(transform); rgb_color top = (rgb_color){ 255, 255, 0, 255 }; rgb_color bottom = (rgb_color){ 0, 255, 255, 255 }; BGradientLinear gradient; gradient.AddColor(top, 0.0f); gradient.AddColor(bottom, 255.0f); gradient.SetStart(rect.LeftTop()); gradient.SetEnd(rect.LeftBottom()); float radius = std::min(rect.Width() / 5, rect.Height() / 5); view->FillRoundRect(rect, radius, radius, gradient); } }; // #pragma mark - NestedStates class NestedStatesTest : public Test { public: NestedStatesTest() : Test("Nested view states") { } virtual void Draw(BView* view, BRect updateRect) { BAffineTransform transform; transform.RotateBy(BPoint(100, 100), 30.0 * M_PI / 180.0); view->SetTransform(transform); rgb_color top = (rgb_color){ 255, 0, 0, 255 }; rgb_color bottom = (rgb_color){ 255, 255, 0, 255 }; BRect rect(20, 20, 120, 120); BGradientLinear gradient; gradient.AddColor(top, 0.0f); gradient.AddColor(bottom, 255.0f); gradient.SetStart(rect.LeftTop()); gradient.SetEnd(rect.LeftBottom()); view->FillRoundRect(rect, 20, 20, gradient); view->PushState(); // Should be in the same place! view->StrokeRoundRect(rect, 20, 20); // Now rotated by another 30 degree view->SetTransform(transform); view->SetDrawingMode(B_OP_ALPHA); view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); view->SetHighColor(0, 0, 255, 120); view->FillRoundRect(rect, 20, 20); view->PopState(); } }; // #pragma mark - Clipping class ClippingTest : public Test { public: ClippingTest() : Test("View bounds clipping") { } virtual void Draw(BView* view, BRect updateRect) { BRect r (20, 20, 50, 50); view->SetHighColor(ui_color(B_FAILURE_COLOR)); view->FillRect(r); BAffineTransform transform; transform.TranslateBy(400, 400); view->SetTransform(transform); // Make sure this rectangle is drawn, even when the original one is out // of the view bounds (for example because of scrolling). view->SetHighColor(ui_color(B_SUCCESS_COLOR)); view->FillRect(r); } }; // #pragma mark - Clipping class TextClippingTest : public Test { public: TextClippingTest() : Test("Text clipping") { } virtual void Draw(BView* view, BRect updateRect) { BFont font; view->GetFont(&font); font.SetSize(70); view->SetFont(&font); float width = view->Bounds().Width(); // The translation make the text, which has negative coordinates, be // visible inside the viewport. BAffineTransform transform; transform.TranslateBy(width, 0); view->SetTransform(transform); const char* str = "CLIPPING"; // Test the standard DrawString method // Draw the text bounds float size = view->StringWidth(str); BRect r(-width, 0, size - width, 70); view->SetHighColor(ui_color(B_SUCCESS_COLOR)); view->FillRect(r); // Draw the text (which should fit inside the bounds rectangle) view->SetHighColor(0, 0, 0, 255); view->DrawString(str, BPoint(-width, 70)); // Test with offset-based DrawString BPoint offsets[strlen(str)]; for(unsigned int i = 0; i < strlen(str); i++) { offsets[i].x = i * 35 - width; offsets[i].y = 145; } // Draw the text bounds view->SetHighColor(ui_color(B_SUCCESS_COLOR)); r = BRect(offsets[0], offsets[strlen(str) - 1]); r.top = 75; view->FillRect(r); // Draw the text (which should fit inside the bounds rectangle) view->SetHighColor(0, 0, 0, 255); view->DrawString(str, offsets, strlen(str)); } }; // #pragma mark - BitmapClipTest class BitmapClipTest : public BitmapTest { public: BitmapClipTest() : BitmapTest("Bitmap clipping") { } virtual void Draw(BView* view, BRect updateRect) { BRect rect(view->Bounds()); if (fBitmap == NULL) { view->SetHighColor(255, 0, 0); view->FillRect(rect); view->SetHighColor(0, 0, 0); view->DrawString("Failed to load the bitmap.", BPoint(20, 20)); return; } rect = fBitmap->Bounds(); view->SetHighColor(ui_color(B_FAILURE_COLOR)); view->FillRect(rect); // The rect offset should compensate the transform translation, so the // bitmap should be drawn at the view origin. It will then exactly // cover the red rectangle, which should not be visible anymore. rect.OffsetBy(0, 40); BAffineTransform transform; transform.TranslateBy(0, -40); view->SetTransform(transform); view->DrawBitmap(fBitmap, fBitmap->Bounds(), rect); } }; // #pragma mark - PixelAlignTest class PixelAlignTest : public Test { public: PixelAlignTest() : Test("Pixel alignment") { } virtual void Draw(BView* view, BRect updateRect) { BRect rect(20, 20, 120, 120); view->SetHighColor(ui_color(B_SUCCESS_COLOR)); view->StrokeRect(rect); BAffineTransform transform; transform.TranslateBy(140, 0); view->SetTransform(transform); // Translating a pixel-aligned rectangle by an integer number of // pixels should result in a pixel-aligned rectangle. view->SetHighColor(ui_color(B_FAILURE_COLOR)); view->StrokeRect(rect); } }; // #pragma mark - int main(int argc, char** argv) { BApplication app(kAppSignature); TestWindow* window = new TestWindow("Transformation tests"); window->AddTest(new RectsTest()); window->AddTest(new BitmapClipTest()); window->AddTest(new TextClippingTest()); window->AddTest(new AlphaMaskBitmapTest()); window->AddTest(new GradientTest()); window->AddTest(new NestedStatesTest()); window->AddTest(new ClippingTest()); window->AddTest(new PixelAlignTest()); window->SetToTest(2); window->Show(); app.Run(); return 0; }