1 /* 2 * Copyright 2001-2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stefano Ceccherini (burton666@libero.it) 8 */ 9 10 /** Style storage used by BTextView */ 11 12 13 #include "InlineInput.h" 14 #include "StyleBuffer.h" 15 16 #include <View.h> 17 18 #include <stdio.h> 19 20 21 _BStyleRunDescBuffer_::_BStyleRunDescBuffer_() 22 : _BTextViewSupportBuffer_<STEStyleRunDesc>(20) 23 { 24 } 25 26 27 void 28 _BStyleRunDescBuffer_::InsertDesc(STEStyleRunDesc* inDesc, int32 index) 29 { 30 InsertItemsAt(1, index, inDesc); 31 } 32 33 34 void 35 _BStyleRunDescBuffer_::RemoveDescs(int32 index, int32 count) 36 { 37 RemoveItemsAt(count, index); 38 } 39 40 41 int32 42 _BStyleRunDescBuffer_::OffsetToRun(int32 offset) const 43 { 44 if (fItemCount <= 1) 45 return 0; 46 47 int32 minIndex = 0; 48 int32 maxIndex = fItemCount; 49 int32 index = 0; 50 51 while (minIndex < maxIndex) { 52 index = (minIndex + maxIndex) >> 1; 53 if (offset >= fBuffer[index].offset) { 54 if (index >= (fItemCount - 1)) { 55 break; 56 } else { 57 if (offset < fBuffer[index + 1].offset) 58 break; 59 else 60 minIndex = index + 1; 61 } 62 } else 63 maxIndex = index; 64 } 65 66 return index; 67 } 68 69 70 void 71 _BStyleRunDescBuffer_::BumpOffset(int32 delta, int32 index) 72 { 73 for (int32 i = index; i < fItemCount; i++) 74 fBuffer[i].offset += delta; 75 } 76 77 78 // #pragma mark - 79 80 81 _BStyleRecordBuffer_::_BStyleRecordBuffer_() 82 : _BTextViewSupportBuffer_<STEStyleRecord>() 83 { 84 } 85 86 87 int32 88 _BStyleRecordBuffer_::InsertRecord(const BFont *inFont, const rgb_color *inColor) 89 { 90 int32 index = 0; 91 92 // look for style in buffer 93 if (MatchRecord(inFont, inColor, &index)) 94 return index; 95 96 // style not found, add it 97 font_height fh; 98 inFont->GetHeight(&fh); 99 100 // check if there's any unused space 101 for (index = 0; index < fItemCount; index++) { 102 if (fBuffer[index].refs < 1) { 103 fBuffer[index].refs = 0; 104 fBuffer[index].ascent = fh.ascent; 105 fBuffer[index].descent = fh.descent + fh.leading; 106 fBuffer[index].style.font = *inFont; 107 fBuffer[index].style.color = *inColor; 108 return index; 109 } 110 } 111 112 // no unused space, expand the buffer 113 const STEStyle style = { *inFont, *inColor }; 114 const STEStyleRecord newRecord = { 115 0, 116 fh.ascent, 117 fh.descent + fh.leading, 118 style 119 }; 120 InsertItemsAt(1, fItemCount, &newRecord); 121 122 return index; 123 } 124 125 126 void 127 _BStyleRecordBuffer_::CommitRecord(int32 index) 128 { 129 fBuffer[index].refs++; 130 } 131 132 133 void 134 _BStyleRecordBuffer_::RemoveRecord(int32 index) 135 { 136 fBuffer[index].refs--; 137 } 138 139 140 bool 141 _BStyleRecordBuffer_::MatchRecord(const BFont *inFont, const rgb_color *inColor, int32 *outIndex) 142 { 143 for (int32 i = 0; i < fItemCount; i++) { 144 if (*inFont == fBuffer[i].style.font 145 && *inColor == fBuffer[i].style.color) { 146 *outIndex = i; 147 return true; 148 } 149 } 150 151 return false; 152 } 153 154 155 // #pragma mark - 156 157 158 static void 159 SetStyleFromMode(uint32 mode, const BFont *fromFont, BFont *toFont, 160 const rgb_color *fromColor, rgb_color *toColor) 161 { 162 if (mode & B_FONT_FAMILY_AND_STYLE) 163 toFont->SetFamilyAndStyle(fromFont->FamilyAndStyle()); 164 165 if (mode & B_FONT_SIZE) 166 toFont->SetSize(fromFont->Size()); 167 168 if (mode & B_FONT_SHEAR) 169 toFont->SetShear(fromFont->Shear()); 170 171 if (!mode || (mode == B_FONT_ALL)) 172 *toColor = *fromColor; 173 } 174 175 176 _BStyleBuffer_::_BStyleBuffer_(const BFont *inFont, const rgb_color *inColor) 177 : 178 fValidNullStyle(true) 179 { 180 fNullStyle.font = *inFont; 181 fNullStyle.color = *inColor; 182 } 183 184 185 void 186 _BStyleBuffer_::InvalidateNullStyle() 187 { 188 fValidNullStyle = false; 189 } 190 191 192 bool 193 _BStyleBuffer_::IsValidNullStyle() const 194 { 195 return fValidNullStyle; 196 } 197 198 199 void 200 _BStyleBuffer_::SyncNullStyle(int32 offset) 201 { 202 if (fValidNullStyle || fStyleRunDesc.ItemCount() < 1) 203 return; 204 205 int32 index = OffsetToRun(offset); 206 fNullStyle = fStyleRecord[fStyleRunDesc[index]->index]->style; 207 208 fValidNullStyle = true; 209 } 210 211 212 void 213 _BStyleBuffer_::SetNullStyle(uint32 inMode, const BFont *inFont, 214 const rgb_color *inColor, int32 offset) 215 { 216 if (fValidNullStyle || fStyleRunDesc.ItemCount() < 1) 217 SetStyleFromMode(inMode, inFont, &fNullStyle.font, inColor, &fNullStyle.color); 218 else { 219 int32 index = OffsetToRun(offset - 1); 220 fNullStyle = fStyleRecord[fStyleRunDesc[index]->index]->style; 221 SetStyleFromMode(inMode, inFont, &fNullStyle.font, inColor, &fNullStyle.color); 222 } 223 224 fValidNullStyle = true; 225 } 226 227 228 void 229 _BStyleBuffer_::GetNullStyle(const BFont **font, const rgb_color **color) const 230 { 231 if (font) 232 *font = &fNullStyle.font; 233 if (color) 234 *color = &fNullStyle.color; 235 } 236 237 238 STEStyleRange * 239 _BStyleBuffer_::AllocateStyleRange(const int32 numStyles) const 240 { 241 STEStyleRange* range = (STEStyleRange *)malloc(sizeof(int32) + sizeof(STEStyleRun) * numStyles); 242 if (range) 243 range->count = numStyles; 244 return range; 245 } 246 247 248 void 249 _BStyleBuffer_::SetStyleRange(int32 fromOffset, int32 toOffset, 250 int32 textLen, uint32 inMode, const BFont *inFont, 251 const rgb_color *inColor) 252 { 253 if (inFont == NULL) 254 inFont = &fNullStyle.font; 255 256 if (inColor == NULL) 257 inColor = &fNullStyle.color; 258 259 if (fromOffset == toOffset) { 260 SetNullStyle(inMode, inFont, inColor, fromOffset); 261 return; 262 } 263 264 if (fStyleRunDesc.ItemCount() < 1) { 265 STEStyleRunDesc newDesc; 266 newDesc.offset = fromOffset; 267 newDesc.index = fStyleRecord.InsertRecord(inFont, inColor); 268 fStyleRunDesc.InsertDesc(&newDesc, 0); 269 fStyleRecord.CommitRecord(newDesc.index); 270 return; 271 } 272 273 int32 offset = fromOffset; 274 int32 runIndex = OffsetToRun(offset); 275 int32 styleIndex = 0; 276 do { 277 const STEStyleRunDesc runDesc = *fStyleRunDesc[runIndex]; 278 int32 runEnd = textLen; 279 if (runIndex < fStyleRunDesc.ItemCount() - 1) 280 runEnd = fStyleRunDesc[runIndex + 1]->offset; 281 282 STEStyle style = fStyleRecord[runDesc.index]->style; 283 SetStyleFromMode(inMode, inFont, &style.font, inColor, &style.color); 284 285 styleIndex = fStyleRecord.InsertRecord(&style.font, &style.color); 286 287 if (runDesc.offset == offset && runIndex > 0 288 && fStyleRunDesc[runIndex - 1]->index == styleIndex) { 289 RemoveStyles(runIndex); 290 runIndex--; 291 } 292 293 if (styleIndex != runDesc.index) { 294 if (offset > runDesc.offset) { 295 STEStyleRunDesc newDesc; 296 newDesc.offset = offset; 297 newDesc.index = styleIndex; 298 fStyleRunDesc.InsertDesc(&newDesc, runIndex + 1); 299 fStyleRecord.CommitRecord(newDesc.index); 300 runIndex++; 301 } else { 302 fStyleRunDesc[runIndex]->index = styleIndex; 303 fStyleRecord.CommitRecord(styleIndex); 304 } 305 306 if (toOffset < runEnd) { 307 STEStyleRunDesc newDesc; 308 newDesc.offset = toOffset; 309 newDesc.index = runDesc.index; 310 fStyleRunDesc.InsertDesc(&newDesc, runIndex + 1); 311 fStyleRecord.CommitRecord(newDesc.index); 312 } 313 } 314 315 runIndex++; 316 offset = runEnd; 317 } while (offset < toOffset); 318 319 if (offset == toOffset && runIndex < fStyleRunDesc.ItemCount() 320 && fStyleRunDesc[runIndex]->index == styleIndex) 321 RemoveStyles(runIndex); 322 } 323 324 325 void 326 _BStyleBuffer_::GetStyle(int32 inOffset, BFont *outFont, rgb_color *outColor) const 327 { 328 if (fStyleRunDesc.ItemCount() < 1) { 329 if (outFont) 330 *outFont = fNullStyle.font; 331 if (outColor) 332 *outColor = fNullStyle.color; 333 return; 334 } 335 336 int32 runIndex = OffsetToRun(inOffset); 337 int32 styleIndex = fStyleRunDesc[runIndex]->index; 338 339 if (outFont) 340 *outFont = fStyleRecord[styleIndex]->style.font; 341 if (outColor) 342 *outColor = fStyleRecord[styleIndex]->style.color; 343 } 344 345 346 STEStyleRange* 347 _BStyleBuffer_::GetStyleRange(int32 startOffset, int32 endOffset) const 348 { 349 int32 startIndex = OffsetToRun(startOffset); 350 int32 endIndex = OffsetToRun(endOffset); 351 352 int32 numStyles = endIndex - startIndex + 1; 353 if (numStyles < 1) 354 numStyles = 1; 355 356 STEStyleRange* result = AllocateStyleRange(numStyles); 357 if (!result) 358 return NULL; 359 360 STEStyleRun* run = &result->runs[0]; 361 for (int32 index = 0; index < numStyles; index++) { 362 *run = (*this)[startIndex + index]; 363 run->offset -= startOffset; 364 if (run->offset < 0) 365 run->offset = 0; 366 run++; 367 } 368 369 return result; 370 } 371 372 373 void 374 _BStyleBuffer_::RemoveStyleRange(int32 fromOffset, int32 toOffset) 375 { 376 int32 fromIndex = fStyleRunDesc.OffsetToRun(fromOffset); 377 int32 toIndex = fStyleRunDesc.OffsetToRun(toOffset) - 1; 378 379 int32 count = toIndex - fromIndex; 380 if (count > 0) { 381 RemoveStyles(fromIndex + 1, count); 382 toIndex = fromIndex; 383 } 384 385 fStyleRunDesc.BumpOffset(fromOffset - toOffset, fromIndex + 1); 386 387 if (toIndex == fromIndex && toIndex < fStyleRunDesc.ItemCount() - 1) { 388 STEStyleRunDesc* runDesc = fStyleRunDesc[toIndex + 1]; 389 runDesc->offset = fromOffset; 390 } 391 392 if (fromIndex < fStyleRunDesc.ItemCount() - 1) { 393 STEStyleRunDesc* runDesc = fStyleRunDesc[fromIndex]; 394 if (runDesc->offset == (runDesc + 1)->offset) { 395 RemoveStyles(fromIndex); 396 fromIndex--; 397 } 398 } 399 400 if (fromIndex >= 0 && fromIndex < fStyleRunDesc.ItemCount() - 1) { 401 STEStyleRunDesc* runDesc = fStyleRunDesc[fromIndex]; 402 if (runDesc->index == (runDesc + 1)->index) 403 RemoveStyles(fromIndex + 1); 404 } 405 } 406 407 408 void 409 _BStyleBuffer_::RemoveStyles(int32 index, int32 count) 410 { 411 for (int32 i = index; i < (index + count); i++) 412 fStyleRecord.RemoveRecord(fStyleRunDesc[i]->index); 413 414 fStyleRunDesc.RemoveDescs(index, count); 415 } 416 417 418 int32 419 _BStyleBuffer_::Iterate(int32 fromOffset, int32 length, _BInlineInput_ *input, 420 const BFont **outFont, const rgb_color **outColor, 421 float *outAscent, float *outDescent, uint32 *) const 422 { 423 // TODO: Handle the _BInlineInput_ style here in some way 424 int32 numRuns = fStyleRunDesc.ItemCount(); 425 if (length < 1 || numRuns < 1) 426 return 0; 427 428 int32 result = length; 429 int32 runIndex = fStyleRunDesc.OffsetToRun(fromOffset); 430 STEStyleRunDesc* run = fStyleRunDesc[runIndex]; 431 432 if (outFont != NULL) 433 *outFont = &fStyleRecord[run->index]->style.font; 434 if (outColor != NULL) 435 *outColor = &fStyleRecord[run->index]->style.color; 436 if (outAscent != NULL) 437 *outAscent = fStyleRecord[run->index]->ascent; 438 if (outDescent != NULL) 439 *outDescent = fStyleRecord[run->index]->descent; 440 441 if (runIndex < numRuns - 1) { 442 int32 nextOffset = (run + 1)->offset - fromOffset; 443 result = min_c(result, nextOffset); 444 } 445 446 return result; 447 } 448 449 450 int32 451 _BStyleBuffer_::OffsetToRun(int32 offset) const 452 { 453 return fStyleRunDesc.OffsetToRun(offset); 454 } 455 456 457 void 458 _BStyleBuffer_::BumpOffset(int32 delta, int32 index) 459 { 460 fStyleRunDesc.BumpOffset(delta, index); 461 } 462 463 464 STEStyleRun 465 _BStyleBuffer_::operator[](int32 index) const 466 { 467 STEStyleRun run; 468 469 if (fStyleRunDesc.ItemCount() < 1) { 470 run.offset = 0; 471 run.style = fNullStyle; 472 } else { 473 STEStyleRunDesc* runDesc = fStyleRunDesc[index]; 474 run.offset = runDesc->offset; 475 run.style = fStyleRecord[runDesc->index]->style; 476 } 477 478 return run; 479 } 480 481 482 // TODO: Horrible name, but can't think of a better one 483 // ? CompareStyles ? 484 // ? FilterStyles ? 485 static void 486 FixupMode(const STEStyle &firstStyle, const STEStyle &otherStyle, uint32 &mode, bool &sameColor) 487 { 488 if (mode & B_FONT_FAMILY_AND_STYLE) { 489 if (firstStyle.font != otherStyle.font) 490 mode &= ~B_FONT_FAMILY_AND_STYLE; 491 } 492 if (mode & B_FONT_SIZE) { 493 if (firstStyle.font.Size() != otherStyle.font.Size()) 494 mode &= ~B_FONT_SIZE; 495 } 496 if (mode & B_FONT_SHEAR) { 497 if (firstStyle.font.Shear() != otherStyle.font.Shear()) 498 mode &= ~B_FONT_SHEAR; 499 } 500 if (firstStyle.color != otherStyle.color) 501 sameColor = false; 502 503 // TODO: Finish this: handle B_FONT_FACE, B_FONT_FLAGS, etc. 504 // if needed 505 } 506 507 508 void 509 _BStyleBuffer_::ContinuousGetStyle(BFont *outFont, uint32 *ioMode, 510 rgb_color *outColor, bool *sameColor, int32 fromOffset, 511 int32 toOffset) const 512 { 513 uint32 mode = B_FONT_ALL; 514 515 if (fStyleRunDesc.ItemCount() < 1) { 516 if (ioMode) 517 *ioMode = mode; 518 if (outFont) 519 *outFont = fNullStyle.font; 520 if (outColor) 521 *outColor = fNullStyle.color; 522 if (sameColor) 523 *sameColor = true; 524 return; 525 } 526 527 int32 fromIndex = OffsetToRun(fromOffset); 528 int32 toIndex = OffsetToRun(toOffset - 1); 529 530 if (fromIndex == toIndex) { 531 int32 styleIndex = fStyleRunDesc[fromIndex]->index; 532 const STEStyle* style = &fStyleRecord[styleIndex]->style; 533 534 if (ioMode) 535 *ioMode = mode; 536 if (outFont) 537 *outFont = style->font; 538 if (outColor) 539 *outColor = style->color; 540 if (sameColor) 541 *sameColor = true; 542 } else { 543 bool oneColor = true; 544 int32 styleIndex = fStyleRunDesc[toIndex]->index; 545 STEStyle theStyle = fStyleRecord[styleIndex]->style; 546 547 for (int32 i = fromIndex; i < toIndex; i++) { 548 styleIndex = fStyleRunDesc[i]->index; 549 FixupMode(fStyleRecord[styleIndex]->style, theStyle, mode, oneColor); 550 } 551 552 if (ioMode) 553 *ioMode = mode; 554 if (outFont) 555 *outFont = theStyle.font; 556 if (outColor) 557 *outColor = theStyle.color; 558 if (sameColor) 559 *sameColor = oneColor; 560 } 561 } 562