Now stacks up group text_runs correctly - previously, the run on the stack could
still be changed by the new group (which lead, surprisingly, to wrong results :). Added \line and \'hh commands (first part of charset support beyond plain ASCII). Renamed GetStyle() to PrepareTextRun(). Added some support functions to copy and compare text_runs. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10577 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
37ec8144ed
commit
0bf9534d45
@ -52,7 +52,7 @@ class TextOutput : public RTF::Worker {
|
||||
virtual void Text(RTF::Text *text);
|
||||
|
||||
private:
|
||||
void GetStyle(text_run *current) throw (status_t);
|
||||
void PrepareTextRun(text_run *current) throw (status_t);
|
||||
|
||||
BDataIO *fTarget;
|
||||
int32 fOffset;
|
||||
@ -133,13 +133,44 @@ next_line(conversion_context &context, const char *prefix,
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
write_unicode_char(conversion_context &context, uint32 c,
|
||||
BDataIO *target) throw (status_t)
|
||||
{
|
||||
size_t length = 1;
|
||||
char bytes[4];
|
||||
|
||||
if (c < 0x80)
|
||||
bytes[0] = c;
|
||||
else if (c < 0x800) {
|
||||
bytes[0] = 0xc0 | (c >> 6);
|
||||
bytes[1] = 0x80 | (c & 0x3f);
|
||||
length = 2;
|
||||
} else if (c < 0x10000) {
|
||||
bytes[0] = 0xe0 | (c >> 12);
|
||||
bytes[1] = 0x80 | ((c >> 6) & 0x3f);
|
||||
bytes[2] = 0x80 | (c & 0x3f);
|
||||
length = 3;
|
||||
} else if (c <= 0x10ffff) {
|
||||
bytes[0] = 0xf0 | (c >> 18);
|
||||
bytes[1] = 0x80 | ((c >> 12) & 0x3f);
|
||||
bytes[2] = 0x80 | ((c >> 6) & 0x3f);
|
||||
bytes[3] = 0x80 | (c & 0x3f);
|
||||
length = 4;
|
||||
}
|
||||
|
||||
write_text(context, bytes, length, target);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
process_command(conversion_context &context, RTF::Command *command,
|
||||
BDataIO *target) throw (status_t)
|
||||
{
|
||||
const char *name = command->Name();
|
||||
|
||||
if (!strcmp(name, "par")) {
|
||||
if (!strcmp(name, "par") || !strcmp(name, "line")) {
|
||||
// paragraph ended
|
||||
return next_line(context, "\n", target);
|
||||
}
|
||||
@ -156,6 +187,10 @@ process_command(conversion_context &context, RTF::Command *command,
|
||||
if (!strcmp(name, "tab")) {
|
||||
return write_text(context, "\t", target);
|
||||
}
|
||||
if (!strcmp(name, "'")) {
|
||||
return write_unicode_char(context, command->Option(), target);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "pard")) {
|
||||
// reset paragraph
|
||||
context.first_line_indent = 0;
|
||||
@ -215,6 +250,57 @@ set_font_face(BFont &font, uint16 face, bool on)
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
text_runs_are_equal(text_run *a, text_run *b)
|
||||
{
|
||||
if (a == NULL && b == NULL)
|
||||
return true;
|
||||
|
||||
if (a == NULL || b == NULL)
|
||||
return false;
|
||||
|
||||
return a->offset == b->offset
|
||||
&& !memcmp(&a->color, &b->color, sizeof(rgb_color))
|
||||
&& a->font == b->font;
|
||||
}
|
||||
|
||||
|
||||
static text_run *
|
||||
copy_text_run(text_run *run)
|
||||
{
|
||||
static const rgb_color kBlack = {0, 0, 0, 255};
|
||||
|
||||
text_run *newRun = new text_run();
|
||||
if (newRun == NULL)
|
||||
throw (status_t)B_NO_MEMORY;
|
||||
|
||||
if (run != NULL) {
|
||||
newRun->offset = run->offset;
|
||||
newRun->font = run->font;
|
||||
newRun->color = run->color;
|
||||
} else {
|
||||
newRun->offset = 0;
|
||||
newRun->color = kBlack;
|
||||
}
|
||||
|
||||
return newRun;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void
|
||||
dump_text_run(text_run *run)
|
||||
{
|
||||
if (run == NULL)
|
||||
return;
|
||||
|
||||
printf("run: offset = %ld, color = {%d,%d,%d}, font = ",
|
||||
run->offset, run->color.red, run->color.green, run->color.blue);
|
||||
run->font.PrintToStream();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@ -277,23 +363,12 @@ TextOutput::FlattenedRunArray(int32 &_size)
|
||||
|
||||
|
||||
void
|
||||
TextOutput::GetStyle(text_run *run) throw (status_t)
|
||||
TextOutput::PrepareTextRun(text_run *run) throw (status_t)
|
||||
{
|
||||
static const rgb_color kBlack = {0, 0, 0, 255};
|
||||
|
||||
if (run != NULL && fOffset == run->offset)
|
||||
return;
|
||||
|
||||
text_run *newRun = new text_run();
|
||||
if (newRun == NULL)
|
||||
throw (status_t)B_NO_MEMORY;
|
||||
|
||||
// take over previous styles
|
||||
if (run != NULL) {
|
||||
newRun->font = run->font;
|
||||
newRun->color = run->color;
|
||||
} else
|
||||
newRun->color = kBlack;
|
||||
text_run *newRun = copy_text_run(run);
|
||||
|
||||
newRun->offset = fOffset;
|
||||
|
||||
@ -305,23 +380,51 @@ TextOutput::GetStyle(text_run *run) throw (status_t)
|
||||
void
|
||||
TextOutput::Group(RTF::Group *group)
|
||||
{
|
||||
if (group->Destination() != RTF::TEXT_DESTINATION)
|
||||
if (group->Destination() != RTF::TEXT_DESTINATION) {
|
||||
Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
fGroupStack.Push(fCurrentRun);
|
||||
if (!fProcessRuns)
|
||||
return;
|
||||
|
||||
// We only push a copy of the run on the stack because the current
|
||||
// run may still be changed in the new group -- later, we'll just
|
||||
// see if that was the case, and either use the copied one then,
|
||||
// or throw it away
|
||||
text_run *run = NULL;
|
||||
if (fCurrentRun != NULL)
|
||||
run = copy_text_run(fCurrentRun);
|
||||
|
||||
fGroupStack.Push(run);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextOutput::GroupEnd(RTF::Group *group)
|
||||
{
|
||||
if (!fProcessRuns)
|
||||
return;
|
||||
|
||||
text_run *last;
|
||||
fGroupStack.Pop(&last);
|
||||
|
||||
// has the style been changed?
|
||||
if (last != NULL && fCurrentRun != NULL
|
||||
&& last->offset != fCurrentRun->offset)
|
||||
GetStyle(last);
|
||||
if (!text_runs_are_equal(last, fCurrentRun)) {
|
||||
if (fCurrentRun != NULL && last != NULL
|
||||
&& fCurrentRun->offset == fOffset) {
|
||||
// replace the current one, we don't need it anymore
|
||||
fCurrentRun->color = last->color;
|
||||
fCurrentRun->font = last->font;
|
||||
delete last;
|
||||
} else if (last) {
|
||||
// adopt the text_run from the previous group
|
||||
last->offset = fOffset;
|
||||
fRuns.AddItem(last);
|
||||
fCurrentRun = last;
|
||||
}
|
||||
} else
|
||||
delete last;
|
||||
}
|
||||
|
||||
|
||||
@ -337,28 +440,28 @@ TextOutput::Command(RTF::Command *command)
|
||||
|
||||
if (!strcmp(name, "cf")) {
|
||||
// foreground color
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
fCurrentRun->color = Start().Color(command->Option());
|
||||
} else if (!strcmp(name, "b")
|
||||
|| !strcmp(name, "embo") || !strcmp(name, "impr")) {
|
||||
// bold style ("emboss" and "engrave" are currently the same, too)
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
set_font_face(fCurrentRun->font, B_BOLD_FACE, command->Option() != 0);
|
||||
} else if (!strcmp(name, "i")) {
|
||||
// bold style
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
set_font_face(fCurrentRun->font, B_ITALIC_FACE, command->Option() != 0);
|
||||
} else if (!strcmp(name, "ul")) {
|
||||
// bold style
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
set_font_face(fCurrentRun->font, B_UNDERSCORE_FACE, command->Option() != 0);
|
||||
} else if (!strcmp(name, "fs")) {
|
||||
// font size in half points
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
fCurrentRun->font.SetSize(command->Option() / 2.0);
|
||||
} else if (!strcmp(name, "plain")) {
|
||||
// reset font to plain style
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
fCurrentRun->font = be_plain_font;
|
||||
} else if (!strcmp(name, "f")) {
|
||||
// font number
|
||||
@ -366,7 +469,7 @@ TextOutput::Command(RTF::Command *command)
|
||||
if (fonts == NULL)
|
||||
return;
|
||||
|
||||
GetStyle(fCurrentRun);
|
||||
PrepareTextRun(fCurrentRun);
|
||||
BFont font;
|
||||
// missing font info will be replaced by the default font
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user