tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / textview_support / StyleBuffer.cpp
blobabf70a5f0cda56a2b0cf22a1dd727ff931e1113b
1 /*
2 * Copyright 2001-2006 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers, mflerackers@androme.be
7 * Stefano Ceccherini, burton666@libero.it
8 */
10 /** Style storage used by BTextView */
13 #include "InlineInput.h"
14 #include "StyleBuffer.h"
16 #include <View.h>
18 #include <stdio.h>
21 // #pragma mark - _BStyleRunDescBuffer_
24 _BStyleRunDescBuffer_::_BStyleRunDescBuffer_()
26 _BTextViewSupportBuffer_<STEStyleRunDesc>(20)
31 void
32 _BStyleRunDescBuffer_::InsertDesc(STEStyleRunDesc* inDesc, int32 index)
34 InsertItemsAt(1, index, inDesc);
38 void
39 _BStyleRunDescBuffer_::RemoveDescs(int32 index, int32 count)
41 RemoveItemsAt(count, index);
45 int32
46 _BStyleRunDescBuffer_::OffsetToRun(int32 offset) const
48 if (fItemCount <= 1)
49 return 0;
51 int32 minIndex = 0;
52 int32 maxIndex = fItemCount;
53 int32 index = 0;
55 while (minIndex < maxIndex) {
56 index = (minIndex + maxIndex) >> 1;
57 if (offset >= fBuffer[index].offset) {
58 if (index >= fItemCount - 1
59 || offset < fBuffer[index + 1].offset) {
60 break;
61 } else
62 minIndex = index + 1;
63 } else
64 maxIndex = index;
67 return index;
71 void
72 _BStyleRunDescBuffer_::BumpOffset(int32 delta, int32 index)
74 for (int32 i = index; i < fItemCount; i++)
75 fBuffer[i].offset += delta;
79 // #pragma mark - _BStyleRecordBuffer_
82 _BStyleRecordBuffer_::_BStyleRecordBuffer_()
84 _BTextViewSupportBuffer_<STEStyleRecord>()
89 int32
90 _BStyleRecordBuffer_::InsertRecord(const BFont* inFont,
91 const rgb_color* inColor)
93 int32 index = 0;
95 // look for style in buffer
96 if (MatchRecord(inFont, inColor, &index))
97 return index;
99 // style not found, add it
100 font_height fh;
101 inFont->GetHeight(&fh);
103 // check if there's any unused space
104 for (index = 0; index < fItemCount; index++) {
105 if (fBuffer[index].refs < 1) {
106 fBuffer[index].refs = 0;
107 fBuffer[index].ascent = fh.ascent;
108 fBuffer[index].descent = fh.descent + fh.leading;
109 fBuffer[index].style.font = *inFont;
110 fBuffer[index].style.color = *inColor;
111 return index;
115 // no unused space, expand the buffer
116 const STEStyle style = { *inFont, *inColor };
117 const STEStyleRecord newRecord = {
119 fh.ascent,
120 fh.descent + fh.leading,
121 style
123 InsertItemsAt(1, fItemCount, &newRecord);
125 return index;
129 void
130 _BStyleRecordBuffer_::CommitRecord(int32 index)
132 fBuffer[index].refs++;
136 void
137 _BStyleRecordBuffer_::RemoveRecord(int32 index)
139 fBuffer[index].refs--;
143 bool
144 _BStyleRecordBuffer_::MatchRecord(const BFont* inFont, const rgb_color* inColor,
145 int32* outIndex)
147 for (int32 i = 0; i < fItemCount; i++) {
148 if (*inFont == fBuffer[i].style.font
149 && *inColor == fBuffer[i].style.color) {
150 *outIndex = i;
151 return true;
155 return false;
159 // #pragma mark - SetStyleFromMode
162 static void
163 SetStyleFromMode(uint32 mode, const BFont* fromFont, BFont* toFont,
164 const rgb_color* fromColor, rgb_color* toColor)
166 if (fromFont != NULL && toFont != NULL) {
167 if ((mode & B_FONT_FAMILY_AND_STYLE) != 0)
168 toFont->SetFamilyAndStyle(fromFont->FamilyAndStyle());
170 if ((mode & B_FONT_FACE) != 0)
171 toFont->SetFace(fromFont->Face());
173 if ((mode & B_FONT_SIZE) != 0)
174 toFont->SetSize(fromFont->Size());
176 if ((mode & B_FONT_SHEAR) != 0)
177 toFont->SetShear(fromFont->Shear());
179 if ((mode & B_FONT_FALSE_BOLD_WIDTH) != 0)
180 toFont->SetFalseBoldWidth(fromFont->FalseBoldWidth());
183 if (fromColor != NULL && toColor != NULL
184 && (mode == 0 || mode == B_FONT_ALL)) {
185 *toColor = *fromColor;
190 // #pragma mark - BTextView::StyleBuffer
193 BTextView::StyleBuffer::StyleBuffer(const BFont* inFont,
194 const rgb_color* inColor)
196 fValidNullStyle(true)
198 fNullStyle.font = *inFont;
199 fNullStyle.color = *inColor;
203 void
204 BTextView::StyleBuffer::InvalidateNullStyle()
206 fValidNullStyle = false;
210 bool
211 BTextView::StyleBuffer::IsValidNullStyle() const
213 return fValidNullStyle;
217 void
218 BTextView::StyleBuffer::SyncNullStyle(int32 offset)
220 if (fValidNullStyle || fStyleRunDesc.ItemCount() < 1)
221 return;
223 int32 index = OffsetToRun(offset);
224 fNullStyle = fStyleRecord[fStyleRunDesc[index]->index]->style;
226 fValidNullStyle = true;
230 void
231 BTextView::StyleBuffer::SetNullStyle(uint32 inMode, const BFont* inFont,
232 const rgb_color* inColor, int32 offset)
234 if (fValidNullStyle || fStyleRunDesc.ItemCount() < 1) {
235 SetStyleFromMode(inMode, inFont, &fNullStyle.font, inColor,
236 &fNullStyle.color);
237 } else {
238 int32 index = OffsetToRun(offset - 1);
239 fNullStyle = fStyleRecord[fStyleRunDesc[index]->index]->style;
240 SetStyleFromMode(inMode, inFont, &fNullStyle.font, inColor,
241 &fNullStyle.color);
244 fValidNullStyle = true;
248 void
249 BTextView::StyleBuffer::GetNullStyle(const BFont** font,
250 const rgb_color** color) const
252 if (font != NULL)
253 *font = &fNullStyle.font;
255 if (color != NULL)
256 *color = &fNullStyle.color;
260 STEStyleRange*
261 BTextView::StyleBuffer::AllocateStyleRange(const int32 numStyles) const
263 STEStyleRange* range = (STEStyleRange*)malloc(sizeof(int32)
264 + sizeof(STEStyleRun) * numStyles);
265 if (range != NULL)
266 range->count = numStyles;
268 return range;
272 void
273 BTextView::StyleBuffer::SetStyleRange(int32 fromOffset, int32 toOffset,
274 int32 textLen, uint32 inMode, const BFont* inFont,
275 const rgb_color* inColor)
277 if (inFont == NULL)
278 inFont = &fNullStyle.font;
280 if (inColor == NULL)
281 inColor = &fNullStyle.color;
283 if (fromOffset == toOffset) {
284 SetNullStyle(inMode, inFont, inColor, fromOffset);
285 return;
288 if (fStyleRunDesc.ItemCount() < 1) {
289 STEStyleRunDesc newDesc;
290 newDesc.offset = fromOffset;
291 newDesc.index = fStyleRecord.InsertRecord(inFont, inColor);
292 fStyleRunDesc.InsertDesc(&newDesc, 0);
293 fStyleRecord.CommitRecord(newDesc.index);
294 return;
297 int32 offset = fromOffset;
298 int32 runIndex = OffsetToRun(offset);
299 int32 styleIndex = 0;
300 do {
301 const STEStyleRunDesc runDesc = *fStyleRunDesc[runIndex];
302 int32 runEnd = textLen;
303 if (runIndex < fStyleRunDesc.ItemCount() - 1)
304 runEnd = fStyleRunDesc[runIndex + 1]->offset;
306 STEStyle style = fStyleRecord[runDesc.index]->style;
307 SetStyleFromMode(inMode, inFont, &style.font, inColor, &style.color);
309 styleIndex = fStyleRecord.InsertRecord(&style.font, &style.color);
311 if (runDesc.offset == offset && runIndex > 0
312 && fStyleRunDesc[runIndex - 1]->index == styleIndex) {
313 RemoveStyles(runIndex);
314 runIndex--;
317 if (styleIndex != runDesc.index) {
318 if (offset > runDesc.offset) {
319 STEStyleRunDesc newDesc;
320 newDesc.offset = offset;
321 newDesc.index = styleIndex;
322 fStyleRunDesc.InsertDesc(&newDesc, runIndex + 1);
323 fStyleRecord.CommitRecord(newDesc.index);
324 runIndex++;
325 } else {
326 fStyleRunDesc[runIndex]->index = styleIndex;
327 fStyleRecord.CommitRecord(styleIndex);
330 if (toOffset < runEnd) {
331 STEStyleRunDesc newDesc;
332 newDesc.offset = toOffset;
333 newDesc.index = runDesc.index;
334 fStyleRunDesc.InsertDesc(&newDesc, runIndex + 1);
335 fStyleRecord.CommitRecord(newDesc.index);
339 runIndex++;
340 offset = runEnd;
341 } while (offset < toOffset);
343 if (offset == toOffset && runIndex < fStyleRunDesc.ItemCount()
344 && fStyleRunDesc[runIndex]->index == styleIndex) {
345 RemoveStyles(runIndex);
350 void
351 BTextView::StyleBuffer::GetStyle(int32 inOffset, BFont* outFont,
352 rgb_color* outColor) const
354 if (fStyleRunDesc.ItemCount() < 1) {
355 if (outFont != NULL)
356 *outFont = fNullStyle.font;
358 if (outColor != NULL)
359 *outColor = fNullStyle.color;
361 return;
364 int32 runIndex = OffsetToRun(inOffset);
365 int32 styleIndex = fStyleRunDesc[runIndex]->index;
367 if (outFont != NULL)
368 *outFont = fStyleRecord[styleIndex]->style.font;
370 if (outColor != NULL)
371 *outColor = fStyleRecord[styleIndex]->style.color;
375 STEStyleRange*
376 BTextView::StyleBuffer::GetStyleRange(int32 startOffset, int32 endOffset) const
378 int32 startIndex = OffsetToRun(startOffset);
379 int32 endIndex = OffsetToRun(endOffset);
381 int32 numStyles = endIndex - startIndex + 1;
382 if (numStyles < 1)
383 numStyles = 1;
385 STEStyleRange* result = AllocateStyleRange(numStyles);
386 if (result == NULL)
387 return NULL;
389 STEStyleRun* run = &result->runs[0];
390 for (int32 index = 0; index < numStyles; index++) {
391 *run = (*this)[startIndex + index];
392 run->offset -= startOffset;
393 if (run->offset < 0)
394 run->offset = 0;
396 run++;
399 return result;
403 void
404 BTextView::StyleBuffer::RemoveStyleRange(int32 fromOffset, int32 toOffset)
406 int32 fromIndex = fStyleRunDesc.OffsetToRun(fromOffset);
407 int32 toIndex = fStyleRunDesc.OffsetToRun(toOffset) - 1;
409 int32 count = toIndex - fromIndex;
410 if (count > 0) {
411 RemoveStyles(fromIndex + 1, count);
412 toIndex = fromIndex;
415 fStyleRunDesc.BumpOffset(fromOffset - toOffset, fromIndex + 1);
417 if (toIndex == fromIndex && toIndex < fStyleRunDesc.ItemCount() - 1) {
418 STEStyleRunDesc* runDesc = fStyleRunDesc[toIndex + 1];
419 runDesc->offset = fromOffset;
422 if (fromIndex < fStyleRunDesc.ItemCount() - 1) {
423 STEStyleRunDesc* runDesc = fStyleRunDesc[fromIndex];
424 if (runDesc->offset == (runDesc + 1)->offset) {
425 RemoveStyles(fromIndex);
426 fromIndex--;
430 if (fromIndex >= 0 && fromIndex < fStyleRunDesc.ItemCount() - 1) {
431 STEStyleRunDesc* runDesc = fStyleRunDesc[fromIndex];
432 if (runDesc->index == (runDesc + 1)->index)
433 RemoveStyles(fromIndex + 1);
438 void
439 BTextView::StyleBuffer::RemoveStyles(int32 index, int32 count)
441 for (int32 i = index; i < index + count; i++)
442 fStyleRecord.RemoveRecord(fStyleRunDesc[i]->index);
444 fStyleRunDesc.RemoveDescs(index, count);
448 int32
449 BTextView::StyleBuffer::Iterate(int32 fromOffset, int32 length,
450 InlineInput* input,
451 const BFont** outFont, const rgb_color** outColor,
452 float* outAscent, float* outDescent, uint32*) const
454 // TODO: Handle the InlineInput style here in some way
455 int32 numRuns = fStyleRunDesc.ItemCount();
456 if (length < 1 || numRuns < 1)
457 return 0;
459 int32 result = length;
460 int32 runIndex = fStyleRunDesc.OffsetToRun(fromOffset);
461 STEStyleRunDesc* run = fStyleRunDesc[runIndex];
463 if (outFont != NULL)
464 *outFont = &fStyleRecord[run->index]->style.font;
466 if (outColor != NULL)
467 *outColor = &fStyleRecord[run->index]->style.color;
469 if (outAscent != NULL)
470 *outAscent = fStyleRecord[run->index]->ascent;
472 if (outDescent != NULL)
473 *outDescent = fStyleRecord[run->index]->descent;
475 if (runIndex < numRuns - 1) {
476 int32 nextOffset = (run + 1)->offset - fromOffset;
477 result = min_c(result, nextOffset);
480 return result;
484 int32
485 BTextView::StyleBuffer::OffsetToRun(int32 offset) const
487 return fStyleRunDesc.OffsetToRun(offset);
491 void
492 BTextView::StyleBuffer::BumpOffset(int32 delta, int32 index)
494 fStyleRunDesc.BumpOffset(delta, index);
498 STEStyleRun
499 BTextView::StyleBuffer::operator[](int32 index) const
501 STEStyleRun run;
503 if (fStyleRunDesc.ItemCount() < 1) {
504 run.offset = 0;
505 run.style = fNullStyle;
506 } else {
507 STEStyleRunDesc* runDesc = fStyleRunDesc[index];
508 run.offset = runDesc->offset;
509 run.style = fStyleRecord[runDesc->index]->style;
512 return run;
516 // TODO: Horrible name, but can't think of a better one
517 // ? CompareStyles ?
518 // ? FilterStyles ?
519 static void
520 FixupMode(const STEStyle &firstStyle, const STEStyle &otherStyle, uint32 &mode,
521 bool &sameColor)
523 if ((mode & B_FONT_FAMILY_AND_STYLE) != 0) {
524 if (firstStyle.font != otherStyle.font)
525 mode &= ~B_FONT_FAMILY_AND_STYLE;
527 if ((mode & B_FONT_SIZE) != 0) {
528 if (firstStyle.font.Size() != otherStyle.font.Size())
529 mode &= ~B_FONT_SIZE;
531 if ((mode & B_FONT_SHEAR) != 0) {
532 if (firstStyle.font.Shear() != otherStyle.font.Shear())
533 mode &= ~B_FONT_SHEAR;
535 if ((mode & B_FONT_FALSE_BOLD_WIDTH) != 0) {
536 if (firstStyle.font.FalseBoldWidth()
537 != otherStyle.font.FalseBoldWidth()) {
538 mode &= ~B_FONT_FALSE_BOLD_WIDTH;
541 if (firstStyle.color != otherStyle.color)
542 sameColor = false;
544 // TODO: Finish this: handle B_FONT_FACE, B_FONT_FLAGS, etc.
545 // if needed
549 void
550 BTextView::StyleBuffer::ContinuousGetStyle(BFont *outFont, uint32* ioMode,
551 rgb_color* outColor, bool* sameColor, int32 fromOffset,
552 int32 toOffset) const
554 uint32 mode = B_FONT_ALL;
556 if (fStyleRunDesc.ItemCount() < 1) {
557 if (ioMode)
558 *ioMode = mode;
560 if (outFont != NULL)
561 *outFont = fNullStyle.font;
563 if (outColor != NULL)
564 *outColor = fNullStyle.color;
566 if (sameColor != NULL)
567 *sameColor = true;
569 return;
572 int32 fromIndex = OffsetToRun(fromOffset);
573 int32 toIndex = OffsetToRun(toOffset - 1);
575 if (fromIndex == toIndex) {
576 int32 styleIndex = fStyleRunDesc[fromIndex]->index;
577 const STEStyle* style = &fStyleRecord[styleIndex]->style;
579 if (ioMode != NULL)
580 *ioMode = mode;
582 if (outFont != NULL)
583 *outFont = style->font;
585 if (outColor != NULL)
586 *outColor = style->color;
588 if (sameColor != NULL)
589 *sameColor = true;
590 } else {
591 bool oneColor = true;
592 int32 styleIndex = fStyleRunDesc[toIndex]->index;
593 STEStyle theStyle = fStyleRecord[styleIndex]->style;
595 for (int32 i = fromIndex; i < toIndex; i++) {
596 styleIndex = fStyleRunDesc[i]->index;
597 FixupMode(fStyleRecord[styleIndex]->style, theStyle, mode,
598 oneColor);
601 if (ioMode != NULL)
602 *ioMode = mode;
604 if (outFont != NULL)
605 *outFont = theStyle.font;
607 if (outColor != NULL)
608 *outColor = theStyle.color;
610 if (sameColor != NULL)
611 *sameColor = oneColor;