spreadsheet: Fix painting issues for rich-text imported by HTMLReader, not fully solved yet.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4261 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-08-09 22:42:20 +00:00
parent baeaf9a230
commit caacb195e4
3 changed files with 120 additions and 93 deletions

View File

@ -385,7 +385,7 @@ begin
ProcessFontStyle(fssBold) ProcessFontStyle(fssBold)
else else
if (NoCaseTag = '<BR>') or (NoCaseTag = '<BR/>') or (pos('<BR ', NoCaseTag) = 1) then if (NoCaseTag = '<BR>') or (NoCaseTag = '<BR/>') or (pos('<BR ', NoCaseTag) = 1) then
FCellText := FCellText + LineEnding; FCellText := FCellText + #10; //LineEnding;
'D': if (NoCaseTag = '<DEL>') then 'D': if (NoCaseTag = '<DEL>') then
ProcessFontStyle(fssStrikeout); ProcessFontStyle(fssStrikeout);
'E': if (NoCaseTag = '<EM>') then 'E': if (NoCaseTag = '<EM>') then
@ -398,12 +398,12 @@ begin
AddRichTextparam(FCurrFont); AddRichTextparam(FCurrFont);
end; end;
'H': case NoCaseTag[3] of 'H': case NoCaseTag[3] of
'1': ProcessFontSizeAndStyle(16, [fssBold]); '1': ProcessFontSizeAndStyle(16, [fssBold]); // <H1>
'2': ProcessFontSizeAndStyle(14, [fssBold]); '2': ProcessFontSizeAndStyle(14, [fssBold]); // <H2>
'3': ProcessFontSizeAndStyle(12, [fssBold]); '3': ProcessFontSizeAndStyle(12, [fssBold]); // <H3>
'4': ProcessFontSizeAndStyle(12, [fssItalic]); '4': ProcessFontSizeAndStyle(12, [fssItalic]); // <H4>
'5': ProcessFontSizeAndStyle(10, [fssBold]); '5': ProcessFontSizeAndStyle(10, [fssBold]); // <H5>
'6': ProcessFontSizeAndStyle(10, [fssItalic]); '6': ProcessFontSizeAndStyle(10, [fssItalic]); // <H6>
end; end;
'I': case NoCaseTag of 'I': case NoCaseTag of
'<I>' : ProcessFontStyle(fssItalic); '<I>' : ProcessFontStyle(fssItalic);
@ -412,7 +412,7 @@ begin
'P': if (NoCaseTag = '<P>') or (pos('<P ', NoCaseTag) = 1) then 'P': if (NoCaseTag = '<P>') or (pos('<P ', NoCaseTag) = 1) then
begin begin
if FCellText <> '' then if FCellText <> '' then
FCellText := FCellText + LineEnding; FCellText := FCellText + #10; //LineEnding;
FFontStack.Push(AddFont(FCurrFont)); FFontStack.Push(AddFont(FCurrFont));
FAttrList.Parse(ActualTag); FAttrList.Parse(ActualTag);
ReadFont(FCurrFont); ReadFont(FCurrFont);
@ -479,7 +479,7 @@ begin
'P': if (NoCaseTag = '</P>') then 'P': if (NoCaseTag = '</P>') then
begin begin
ProcessFontRestore; ProcessFontRestore;
if FCellText <> '' then FCellText := FCellText + LineEnding; if FCellText <> '' then FCellText := FCellText + #10; //LineEnding;
end; end;
'S': if (NoCaseTag = '</SUB>') or (NoCaseTag = '</SUP>') or 'S': if (NoCaseTag = '</SUB>') or (NoCaseTag = '</SUP>') or
(NoCaseTag = '</S>') or (NoCaseTag = '</SPAN>') or (NoCaseTag = '</S>') or (NoCaseTag = '</SPAN>') or
@ -918,38 +918,41 @@ begin
// The next tags are processed only within a <TD> or <TH> context. // The next tags are processed only within a <TD> or <TH> context.
ProcessCellTags(NoCaseTag, ActualTag); ProcessCellTags(NoCaseTag, ActualTag);
(*
{
if (pos('<H', NoCaseTag) = 1) and (NoCaseTag[3] in ['1'..'9']) then
begin
if FInCell then
FInHeader := true;
end else }
else
case NoCaseTag of
'</SPAN>':
if FInCell then FInSpan := false;
'<H1/>', '<H2/>', '<H3/>', '<H4/>', '<H5/>', '<H6/>':
if FinCell then FInHeader := false;
'<TD/>', '<TD />', '<TH/>', '<TH />': // empty cells
if FInCell then
inc(FCurrCol);
end;
*)
end; end;
procedure TsHTMLReader.TextFoundHandler(AText: String); procedure TsHTMLReader.TextFoundHandler(AText: String);
// Todo: find correct way to retain spaces
// Example:
// <td>123<b>abc</b> is rendered by browser as 123abc (with abc bold)
// <td>123
// <b>abc</b> is rendered as 123 abc
// The current way is not good.
var
beginsWithLineEnding, endsWithLineEnding: Boolean;
begin begin
if FInCell then if FInCell then
begin begin
beginsWithLineEnding := (AText <> '') and (AText[1] in [#13, #10]);
endsWithLineEnding := (AText <> '') and (AText[Length(AText)] in [#13,#10]);
AText := CleanHTMLString(ConvertEncoding(AText, FEncoding, EncodingUTF8)); AText := CleanHTMLString(ConvertEncoding(AText, FEncoding, EncodingUTF8));
if AText <> '' then if AText <> '' then
begin begin
if FCellText = '' then if FCellText = '' then
FCellText := AText FCellText := AText
else
if beginsWithLineEnding then
FCellText := FCellText + ' ' + AText
else
if endsWithLineEnding then
FCelLText := FCelLText + AText + ' '
else
FCellText := FCellText + AText;
{
if FCellText[Length(FCellText)] = #10 then
FCellText := FCellText + AText
else else
FCellText := FCellText + ' ' + AText; FCellText := FCellText + ' ' + AText;
}
end; end;
end; end;
end; end;

View File

@ -1991,7 +1991,8 @@ begin
begin begin
// merged cells // merged cells
FDrawingCell := Worksheet.FindMergeBase(cell); FDrawingCell := Worksheet.FindMergeBase(cell);
Worksheet.FindMergedRange(FDrawingCell, sr1, sc1, sr2, sc2); if Worksheet.FindMergedRange(FDrawingCell, sr1, sc1, sr2, sc2) then
begin
gr := GetGridRow(sr1); gr := GetGridRow(sr1);
if Worksheet.HasComment(FDrawingCell) then if Worksheet.HasComment(FDrawingCell) then
commentcell_rct := CellRect(GetGridCol(sc2), gr) commentcell_rct := CellRect(GetGridCol(sc2), gr)
@ -2003,6 +2004,7 @@ begin
gcNext := gc + (sc2 - sc1) + 1; gcNext := gc + (sc2 - sc1) + 1;
end; end;
end; end;
end;
ColRowToOffset(true, true, gc, rct.Left, tmp); ColRowToOffset(true, true, gc, rct.Left, tmp);
ColRowToOffset(true, true, gcNext-1, tmp, rct.Right); ColRowToOffset(true, true, gcNext-1, tmp, rct.Right);

View File

@ -270,14 +270,15 @@ var
procedure ScanLine(var P: PChar; var NumSpaces: Integer; procedure ScanLine(var P: PChar; var NumSpaces: Integer;
var ARtpFontIndex: Integer; var ALineWidth, ALineHeight: Integer); var ARtpFontIndex: Integer; var ALineWidth, ALineHeight: Integer);
var var
pEOL: PChar; pWordStart: PChar;
EOL: Boolean;
savedSpaces: Integer; savedSpaces: Integer;
savedWidth: Integer; savedWidth: Integer;
savedRtpIndex: Integer; savedCharPos: Integer;
savedRtpFontIndex: Integer;
maxWidth: Integer; maxWidth: Integer;
dw: Integer; dw: Integer;
spaceFound: Boolean; lineChar: utf8String;
s: utf8String;
charLen: Integer; // Number of bytes of current utf8 character charLen: Integer; // Number of bytes of current utf8 character
begin begin
NumSpaces := 0; NumSpaces := 0;
@ -286,9 +287,6 @@ var
ALineWidth := 0; ALineWidth := 0;
savedWidth := 0; savedWidth := 0;
savedSpaces := 0; savedSpaces := 0;
savedRtpIndex := ARtpFontIndex;
spaceFound := false;
pEOL := p;
if AWordwrap then if AWordwrap then
begin begin
@ -300,67 +298,89 @@ var
else else
maxWidth := MaxInt; maxWidth := MaxInt;
while p^ <> #0 do begin
UpdateFont(charPos, ARtpFontIndex, fontHeight, fontPos); UpdateFont(charPos, ARtpFontIndex, fontHeight, fontPos);
ALineHeight := Max(fontHeight, ALineHeight); ALineHeight := Max(fontHeight, ALineHeight);
s := UnicodeToUTF8(UTF8CharacterToUnicode(p, charLen)); while p^ <> #0 do begin
case p^ of case p^ of
' ': begin
spaceFound := true;
pEOL := p;
savedWidth := ALineWidth;
savedSpaces := NumSpaces;
savedRtpIndex := ARtpFontIndex;
dw := Math.IfThen(ARotation = rtStacked, fontHeight, ACanvas.TextWidth(s));
if ALineWidth + dw < MaxWidth then
begin
inc(NumSpaces);
ALineWidth := ALineWidth + dw;
end else
break;
end;
#13: begin #13: begin
inc(p); inc(p);
inc(charPos); inc(charpos);
if p^ = #10 then if p^ = #10 then
begin begin
inc(p); inc(p);
inc(charPos); inc(charpos);
end;
break; break;
end; end;
end;
#10: begin #10: begin
inc(p); inc(p);
inc(charPos); inc(charpos);
break; break;
end; end;
' ': begin
savedWidth := ALineWidth;
savedSpaces := NumSpaces;
// Find next word
while p^ = ' ' do
begin
UpdateFont(charPos, ARtpFontIndex, fontHeight, fontPos);
ALineHeight := Max(fontHeight, ALineHeight);
dw := Math.IfThen(ARotation = rtStacked, fontHeight, ACanvas.TextWidth(' '));
ALineWidth := ALineWidth + dw;
inc(NumSpaces);
inc(p);
inc(charPos);
end;
if ALineWidth >= maxWidth then
begin
ALineWidth := savedWidth;
NumSpaces := savedSpaces;
break;
end;
end;
else begin else begin
dw := Math.IfThen(ARotation = rtStacked, fontHeight, ACanvas.TextWidth(s)); // Bere begins a new word. Find end of this word and check if
// it fits into the line.
// Store the data valid for the word start.
pWordStart := p;
savedCharPos := charpos;
savedRtpFontIndex := ARtpFontIndex;
EOL := false;
while (p^ <> #0) and (p^ <> #13) and (p^ <> #10) and (p^ <> ' ') do
begin
UpdateFont(charPos, ARtpFontIndex, fontHeight, fontPos);
ALineHeight := Max(fontHeight, ALineHeight);
lineChar := UnicodeToUTF8(UTF8CharacterToUnicode(p, charLen));
dw := Math.IfThen(ARotation = rtStacked, fontHeight, ACanvas.TextWidth(lineChar));
ALineWidth := ALineWidth + dw; ALineWidth := ALineWidth + dw;
if ALineWidth > maxWidth then if ALineWidth > maxWidth then
begin begin
if spaceFound then // The line exeeds the max line width.
// There are two cases:
if NumSpaces > 0 then
begin begin
p := pEOL; // (a) This is not the only word: Go back to where this
// word began. We had stored everything needed!
p := pWordStart;
charpos := savedCharPos;
ALineWidth := savedWidth; ALineWidth := savedWidth;
NumSpaces := savedSpaces; ARtpFontIndex := savedRtpFontIndex;
ARtpFontIndex := savedRtpIndex;
end else
begin
ALineWidth := ALineWidth - dw;
if ALineWidth = 0 then
inc(p);
end; end;
// (b) This is the only word in the line --> we break at the
// current cursor position.
EOL := true;
break; break;
end; end;
end; inc(p);
end;
inc(p, charLen);
inc(charPos); inc(charPos);
end; end;
if EOL then break;
end;
end;
end;
UpdateFont(charPos, ARtpFontIndex, fontHeight, fontPos); UpdateFont(charPos, ARtpFontIndex, fontHeight, fontPos);
ALineHeight := Max(fontHeight, ALineHeight);
end; end;
{ Paints the text between the pointers pStart and pEnd. { Paints the text between the pointers pStart and pEnd.
@ -482,11 +502,13 @@ begin
totalHeight := totalHeight + Height; totalHeight := totalHeight + Height;
linelen := Max(linelen, Width); linelen := Max(linelen, Width);
p := pEnd; p := pEnd;
{
if p^ = ' ' then if p^ = ' ' then
while (p^ <> #0) and (p^ = ' ') do begin while (p^ <> #0) and (p^ = ' ') do begin
inc(p); inc(p);
inc(charPos); inc(charPos);
end; end;
}
end; end;
until p^ = #0; until p^ = #0;