1 /* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Mikael Konradson, mikael.konradson@gmail.com 7 */ 8 9 10 #include "FontDemoView.h" 11 12 #include <math.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <string.h> 16 17 #include <Catalog.h> 18 #include <Bitmap.h> 19 #include <Font.h> 20 #include <Message.h> 21 #include <Shape.h> 22 #include <String.h> 23 #include <StackOrHeapArray.h> 24 25 #include "messages.h" 26 27 #undef B_TRANSLATION_CONTEXT 28 #define B_TRANSLATION_CONTEXT "FontDemoView" 29 30 FontDemoView::FontDemoView(BRect rect) 31 : BView(rect, "FontDemoView", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS), 32 fBitmap(NULL), 33 fBufferView(NULL), 34 fFontSize(50.0), 35 fSpacing(0.0), 36 fOutLineLevel(0), 37 fDrawingMode(B_OP_COPY), 38 fBoundingBoxes(false), 39 fDrawShapes(false), 40 fShapes(NULL) 41 { 42 SetViewColor(B_TRANSPARENT_COLOR); 43 BString setStr = B_TRANSLATE("Haiku, Inc."); 44 SetString(setStr); 45 SetFontSize(fFontSize); 46 SetAntialiasing(true); 47 48 _NewBitmap(Bounds()); 49 } 50 51 52 FontDemoView::~FontDemoView() 53 { 54 free(fShapes); 55 56 fBitmap->Lock(); 57 delete fBitmap; 58 } 59 60 61 void 62 FontDemoView::FrameResized(float width, float height) 63 { 64 // TODO: We shouldnt invalidate the whole view when bounding boxes are 65 // working as wanted 66 Invalidate(/*fBoxRegion.Frame()*/); 67 BView::FrameResized(width, height); 68 } 69 70 71 void 72 FontDemoView::Draw(BRect updateRect) 73 { 74 BRect rect = Bounds(); 75 fBufferView = _GetView(rect); 76 _DrawView(fBufferView); 77 78 fBufferView->Sync(); 79 DrawBitmap(fBitmap, rect); 80 fBitmap->Unlock(); 81 } 82 83 84 void 85 FontDemoView::_DrawView(BView* view) 86 { 87 if (!view) 88 return; 89 90 view->SetDrawingMode(B_OP_COPY); 91 92 93 BRect rect = view->Bounds(); 94 view->SetHighColor(255, 255, 255); 95 view->FillRect(rect); 96 97 if (!fString) 98 return; 99 100 view->SetFont(&fFont, B_FONT_ALL); 101 102 const size_t size = fString.CountChars(); 103 BStackOrHeapArray<BRect, 64> boundBoxes(size); 104 105 if (OutLineLevel()) 106 fFont.GetGlyphShapes(fString, size, fShapes); 107 else 108 fFont.GetBoundingBoxesAsGlyphs(fString, size, B_SCREEN_METRIC, boundBoxes); 109 110 float escapementArray[size]; 111 //struct escapement_delta escapeDeltas[size]; 112 struct edge_info edgeInfo[size]; 113 /* 114 for (size_t j = 0; j < size; j++) { 115 escapeDeltas[j].nonspace = 0.0f; 116 escapeDeltas[j].space = 0.0f; 117 } 118 */ 119 fFont.GetEdges(fString.String(), size, edgeInfo); 120 fFont.GetEscapements(fString.String(), size, /*escapeDeltas,*/ escapementArray); 121 122 font_height fh; 123 fFont.GetHeight(&fh); 124 125 float xCoordArray[size]; 126 float yCoordArray[size]; 127 128 float yCoord = (rect.Height() + fh.ascent - fh.descent) / 2; 129 float xCoord = -rect.Width() / 2; 130 const float xCenter = xCoord * -1; 131 const float r = Rotation() * (M_PI / 180.0); 132 const float cosinus = cos(r); 133 const float sinus = -sin(r); 134 135 // When the bounding boxes workes properly we will invalidate only the 136 // region area instead of the whole view. 137 138 fBoxRegion.MakeEmpty(); 139 140 for (size_t i = 0; i < size; i++) { 141 xCoordArray[i] = 0.0f; 142 yCoordArray[i] = 0.0f; 143 144 yCoordArray[i] = sinus * (xCoord - xCoordArray[i]); 145 xCoordArray[i] = cosinus * xCoord; 146 147 xCoordArray[i] += xCenter; 148 yCoordArray[i] += yCoord; 149 150 boundBoxes[i].OffsetBy(xCoordArray[i], yCoordArray[i]); 151 152 if (OutLineLevel()) { 153 view->MovePenTo(xCoordArray[i], yCoordArray[i]); 154 view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 155 view->FillShape(fShapes[i]); 156 view->SetPenSize(OutLineLevel()); 157 view->SetHighColor(0, 0, 0); 158 view->StrokeShape(fShapes[i]); 159 } else { 160 view->SetHighColor(0, 0, 0); 161 view->SetDrawingMode(fDrawingMode); 162 int32 charLength; 163 const char* charAt = fString.CharAt(i, &charLength); 164 view->DrawString(charAt, charLength, 165 BPoint(xCoordArray[i], yCoordArray[i])); 166 } 167 168 if (BoundingBoxes() && !OutLineLevel()) { 169 if (i % 2) 170 view->SetHighColor(0, 255, 0); 171 else 172 view->SetHighColor(255, 0, 0); 173 view->SetDrawingMode(B_OP_COPY); 174 view->StrokeRect(boundBoxes[i]); 175 } 176 177 // add the bounding to the region. 178 fBoxRegion.Include(boundBoxes[i]); 179 180 xCoord += (escapementArray[i] /*+ escapeDeltas[i].nonspace + escapeDeltas[i].space*/) 181 * FontSize() + Spacing(); 182 //printf("xCoord %f\n", xCoord); 183 } 184 } 185 186 187 void 188 FontDemoView::MessageReceived(BMessage* msg) 189 { 190 switch (msg->what) { 191 case TEXT_CHANGED_MSG: 192 { 193 BString text; 194 if (msg->FindString("_text", &text) == B_OK) { 195 SetString(text); 196 Invalidate(/*&fBoxRegion*/); 197 } 198 break; 199 } 200 201 case FONTSTYLE_CHANGED_MSG: 202 { 203 BMessage fontMessage; 204 if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK) 205 return; 206 207 const char* family; 208 const char* style; 209 if (fontMessage.FindString("_family", &family) != B_OK 210 || fontMessage.FindString("_style", &style) != B_OK) 211 return; 212 213 fFont.SetFamilyAndStyle(family, style); 214 Invalidate(); 215 break; 216 } 217 218 case FONTFAMILY_CHANGED_MSG: 219 { 220 BMessage fontMessage; 221 if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK) 222 return; 223 224 const char* family; 225 if (fontMessage.FindString("_family", &family) != B_OK) 226 return; 227 228 font_style style; 229 if (get_font_style(const_cast<char*>(family), 0, &style) == B_OK) { 230 fFont.SetFamilyAndStyle(family, style); 231 Invalidate(/*&fBoxRegion*/); 232 } 233 break; 234 } 235 236 case FONTSIZE_MSG: 237 { 238 float size = 0.0; 239 if (msg->FindFloat("_size", &size) == B_OK) { 240 SetFontSize(size); 241 Invalidate(/*&fBoxRegion*/); 242 } 243 break; 244 } 245 246 case FONTSHEAR_MSG: 247 { 248 float shear = 90.0; 249 if (msg->FindFloat("_shear", &shear) == B_OK) { 250 SetFontShear(shear); 251 Invalidate(/*&fBoxRegion*/); 252 } 253 break; 254 } 255 256 case ROTATION_MSG: 257 { 258 float rotation = 0.0; 259 if (msg->FindFloat("_rotation", &rotation) == B_OK) { 260 SetFontRotation(rotation); 261 Invalidate(/*&fBoxRegion*/); 262 } 263 break; 264 } 265 266 case SPACING_MSG: 267 { 268 float space = 0.0; 269 if (msg->FindFloat("_spacing", &space) == B_OK) { 270 SetSpacing(space); 271 Invalidate(/*&fBoxRegion*/); 272 } 273 break; 274 } 275 276 case OUTLINE_MSG: 277 { 278 int8 outline = 0; 279 if (msg->FindInt8("_outline", &outline) == B_OK) { 280 SetOutlineLevel(outline); 281 Invalidate(/*&fBoxRegion*/); 282 } 283 break; 284 } 285 286 case ALIASING_MSG: 287 { 288 bool aliased = false; 289 if (msg->FindBool("_aliased", &aliased) == B_OK) { 290 SetAntialiasing(aliased); 291 Invalidate(/*&fBoxRegion*/); 292 } 293 break; 294 } 295 296 case DRAWINGMODE_CHANGED_MSG: 297 { 298 if (msg->FindInt32("_mode", (int32 *)&fDrawingMode) == B_OK) { 299 Invalidate(/*&fBoxRegion*/); 300 switch (fDrawingMode) { 301 case B_OP_COPY: 302 printf("Drawing mode: B_OP_COPY\n"); 303 break; 304 case B_OP_OVER: 305 printf("Drawing mode: B_OP_OVER\n"); 306 break; 307 case B_OP_ERASE: 308 printf("Drawing mode: B_OP_ERASE\n"); 309 break; 310 case B_OP_INVERT: 311 printf("Drawing mode: B_OP_INVERT\n"); 312 break; 313 case B_OP_ADD: 314 printf("Drawing mode: B_OP_ADD\n"); 315 break; 316 case B_OP_SUBTRACT: 317 printf("Drawing mode: B_OP_SUBTRACT\n"); 318 break; 319 case B_OP_BLEND: 320 printf("Drawing mode: B_OP_BLEND\n"); 321 break; 322 case B_OP_MIN: 323 printf("Drawing mode: B_OP_MIN\n"); 324 break; 325 case B_OP_MAX: 326 printf("Drawing mode: B_OP_MAX\n"); 327 break; 328 case B_OP_SELECT: 329 printf("Drawing mode: B_OP_SELECT\n"); 330 break; 331 case B_OP_ALPHA: 332 printf("Drawing mode: B_OP_ALPHA\n"); 333 break; 334 default: 335 printf("Drawing mode: %d\n", fDrawingMode); 336 } 337 } 338 break; 339 } 340 341 case BOUNDING_BOX_MSG: 342 { 343 bool boundingbox = false; 344 if (msg->FindBool("_boundingbox", &boundingbox) == B_OK) { 345 SetDrawBoundingBoxes(boundingbox); 346 Invalidate(/*&fBoxRegion*/); 347 } 348 break; 349 } 350 351 default: 352 BView::MessageReceived(msg); 353 break; 354 } 355 } 356 357 358 void 359 FontDemoView::SetString(BString string) 360 { 361 fString = string; 362 free(fShapes); 363 _AddShapes(fString); 364 } 365 366 367 BString 368 FontDemoView::String() const 369 { 370 return fString; 371 } 372 373 374 void 375 FontDemoView::SetFontSize(float size) 376 { 377 fFont.SetSize(size); 378 } 379 380 381 void 382 FontDemoView::SetFontShear(float shear) 383 { 384 fFont.SetShear(shear); 385 } 386 387 388 void 389 FontDemoView::SetFontRotation(float rotation) 390 { 391 fFont.SetRotation(rotation); 392 } 393 394 395 void 396 FontDemoView::SetDrawBoundingBoxes(bool state) 397 { 398 fBoundingBoxes = state; 399 } 400 401 402 void 403 FontDemoView::SetAntialiasing(bool state) 404 { 405 fFont.SetFlags(state ? B_FORCE_ANTIALIASING : B_DISABLE_ANTIALIASING); 406 } 407 408 409 void 410 FontDemoView::SetSpacing(float space) 411 { 412 fSpacing = space; 413 } 414 415 416 void 417 FontDemoView::SetOutlineLevel(int8 outline) 418 { 419 fOutLineLevel = outline; 420 } 421 422 423 void 424 FontDemoView::_AddShapes(BString string) 425 { 426 const size_t size = string.CountChars(); 427 fShapes = (BShape**)malloc(sizeof(BShape*) * size); 428 429 for (size_t i = 0; i < size; i++) { 430 fShapes[i] = new BShape(); 431 } 432 } 433 434 435 BView* 436 FontDemoView::_GetView(BRect rect) 437 { 438 if (!fBitmap || fBitmap->Bounds() != rect) 439 _NewBitmap(rect); 440 441 fBitmap->Lock(); 442 return fBitmap->ChildAt(0); 443 } 444 445 446 void 447 FontDemoView::_NewBitmap(BRect rect) 448 { 449 delete fBitmap; 450 fBitmap = new BBitmap(rect, B_RGB16, true); 451 452 if (fBitmap->Lock()) { 453 BView* view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW); 454 fBitmap->AddChild(view); 455 fBitmap->Unlock(); 456 } else { 457 delete fBitmap; 458 fBitmap = NULL; 459 } 460 } 461