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