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:
@@ -52,7 +52,7 @@ class TextOutput : public RTF::Worker {
|
|||||||
virtual void Text(RTF::Text *text);
|
virtual void Text(RTF::Text *text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GetStyle(text_run *current) throw (status_t);
|
void PrepareTextRun(text_run *current) throw (status_t);
|
||||||
|
|
||||||
BDataIO *fTarget;
|
BDataIO *fTarget;
|
||||||
int32 fOffset;
|
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
|
static size_t
|
||||||
process_command(conversion_context &context, RTF::Command *command,
|
process_command(conversion_context &context, RTF::Command *command,
|
||||||
BDataIO *target) throw (status_t)
|
BDataIO *target) throw (status_t)
|
||||||
{
|
{
|
||||||
const char *name = command->Name();
|
const char *name = command->Name();
|
||||||
|
|
||||||
if (!strcmp(name, "par")) {
|
if (!strcmp(name, "par") || !strcmp(name, "line")) {
|
||||||
// paragraph ended
|
// paragraph ended
|
||||||
return next_line(context, "\n", target);
|
return next_line(context, "\n", target);
|
||||||
}
|
}
|
||||||
@@ -156,6 +187,10 @@ process_command(conversion_context &context, RTF::Command *command,
|
|||||||
if (!strcmp(name, "tab")) {
|
if (!strcmp(name, "tab")) {
|
||||||
return write_text(context, "\t", target);
|
return write_text(context, "\t", target);
|
||||||
}
|
}
|
||||||
|
if (!strcmp(name, "'")) {
|
||||||
|
return write_unicode_char(context, command->Option(), target);
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(name, "pard")) {
|
if (!strcmp(name, "pard")) {
|
||||||
// reset paragraph
|
// reset paragraph
|
||||||
context.first_line_indent = 0;
|
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -277,23 +363,12 @@ TextOutput::FlattenedRunArray(int32 &_size)
|
|||||||
|
|
||||||
|
|
||||||
void
|
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)
|
if (run != NULL && fOffset == run->offset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
text_run *newRun = new text_run();
|
text_run *newRun = copy_text_run(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;
|
|
||||||
|
|
||||||
newRun->offset = fOffset;
|
newRun->offset = fOffset;
|
||||||
|
|
||||||
@@ -305,23 +380,51 @@ TextOutput::GetStyle(text_run *run) throw (status_t)
|
|||||||
void
|
void
|
||||||
TextOutput::Group(RTF::Group *group)
|
TextOutput::Group(RTF::Group *group)
|
||||||
{
|
{
|
||||||
if (group->Destination() != RTF::TEXT_DESTINATION)
|
if (group->Destination() != RTF::TEXT_DESTINATION) {
|
||||||
Skip();
|
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
|
void
|
||||||
TextOutput::GroupEnd(RTF::Group *group)
|
TextOutput::GroupEnd(RTF::Group *group)
|
||||||
{
|
{
|
||||||
|
if (!fProcessRuns)
|
||||||
|
return;
|
||||||
|
|
||||||
text_run *last;
|
text_run *last;
|
||||||
fGroupStack.Pop(&last);
|
fGroupStack.Pop(&last);
|
||||||
|
|
||||||
// has the style been changed?
|
// has the style been changed?
|
||||||
if (last != NULL && fCurrentRun != NULL
|
if (!text_runs_are_equal(last, fCurrentRun)) {
|
||||||
&& last->offset != fCurrentRun->offset)
|
if (fCurrentRun != NULL && last != NULL
|
||||||
GetStyle(last);
|
&& 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")) {
|
if (!strcmp(name, "cf")) {
|
||||||
// foreground color
|
// foreground color
|
||||||
GetStyle(fCurrentRun);
|
PrepareTextRun(fCurrentRun);
|
||||||
fCurrentRun->color = Start().Color(command->Option());
|
fCurrentRun->color = Start().Color(command->Option());
|
||||||
} else if (!strcmp(name, "b")
|
} else if (!strcmp(name, "b")
|
||||||
|| !strcmp(name, "embo") || !strcmp(name, "impr")) {
|
|| !strcmp(name, "embo") || !strcmp(name, "impr")) {
|
||||||
// bold style ("emboss" and "engrave" are currently the same, too)
|
// 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);
|
set_font_face(fCurrentRun->font, B_BOLD_FACE, command->Option() != 0);
|
||||||
} else if (!strcmp(name, "i")) {
|
} else if (!strcmp(name, "i")) {
|
||||||
// bold style
|
// bold style
|
||||||
GetStyle(fCurrentRun);
|
PrepareTextRun(fCurrentRun);
|
||||||
set_font_face(fCurrentRun->font, B_ITALIC_FACE, command->Option() != 0);
|
set_font_face(fCurrentRun->font, B_ITALIC_FACE, command->Option() != 0);
|
||||||
} else if (!strcmp(name, "ul")) {
|
} else if (!strcmp(name, "ul")) {
|
||||||
// bold style
|
// bold style
|
||||||
GetStyle(fCurrentRun);
|
PrepareTextRun(fCurrentRun);
|
||||||
set_font_face(fCurrentRun->font, B_UNDERSCORE_FACE, command->Option() != 0);
|
set_font_face(fCurrentRun->font, B_UNDERSCORE_FACE, command->Option() != 0);
|
||||||
} else if (!strcmp(name, "fs")) {
|
} else if (!strcmp(name, "fs")) {
|
||||||
// font size in half points
|
// font size in half points
|
||||||
GetStyle(fCurrentRun);
|
PrepareTextRun(fCurrentRun);
|
||||||
fCurrentRun->font.SetSize(command->Option() / 2.0);
|
fCurrentRun->font.SetSize(command->Option() / 2.0);
|
||||||
} else if (!strcmp(name, "plain")) {
|
} else if (!strcmp(name, "plain")) {
|
||||||
// reset font to plain style
|
// reset font to plain style
|
||||||
GetStyle(fCurrentRun);
|
PrepareTextRun(fCurrentRun);
|
||||||
fCurrentRun->font = be_plain_font;
|
fCurrentRun->font = be_plain_font;
|
||||||
} else if (!strcmp(name, "f")) {
|
} else if (!strcmp(name, "f")) {
|
||||||
// font number
|
// font number
|
||||||
@@ -366,7 +469,7 @@ TextOutput::Command(RTF::Command *command)
|
|||||||
if (fonts == NULL)
|
if (fonts == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GetStyle(fCurrentRun);
|
PrepareTextRun(fCurrentRun);
|
||||||
BFont font;
|
BFont font;
|
||||||
// missing font info will be replaced by the default font
|
// missing font info will be replaced by the default font
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user