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