feat: para balance improvements

This commit is contained in:
Georgy Litvinov 2021-08-23 18:01:29 +02:00
parent c5dfb15133
commit 79f8164650
2 changed files with 225 additions and 63 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Archive" script:language="StarBasic" script:moduleType="normal">Sub archMark20 <script:module xmlns:script="http://openoffice.org/2000/script" script:name="Archive" script:language="StarBasic" script:moduleType="normal">Sub archMark21
End Sub End Sub
@ -441,10 +441,27 @@ Sub stretchPrevPage()
oViewCursor.goToRange(oSavePosition,false) oViewCursor.goToRange(oSavePosition,false)
End Sub End Sub
Sub adjustLastLineCurPara()
Dim oViewCursor As Object
Dim oTextCursor As Object
Dim paraEnd As Object
oViewCursor = ThisComponent.CurrentController.getViewCursor()
oTextCursor = oViewCursor.Text.CreateTextCursorByRange(oViewCursor)
paraEnd = getParaEnd(oTextCursor)
oTextCursor.goToRange(paraEnd,false)
oTextCursor.goLeft(1,true)
If (oTextCursor.String = &quot; &quot;) Then
oTextCursor.String = &quot;&quot;
EndIf
oTextCursor.ParaIsHyphenation = true
adjustLastLine(oTextCursor.Start)
End Sub
Sub adjustLastLine(anchor As Object) Sub adjustLastLine(anchor As Object)
anchor.ParaAdjust = 2 anchor.ParaAdjust = 2
&apos;anchor.ParaLastLineAdjust = 2 anchor.ParaLastLineAdjust = 2
balancePara(anchor) balancePara(anchor)
End Sub End Sub
@ -478,77 +495,221 @@ Sub balancePara(targetPara As Object)
Dim lineCount As Integer Dim lineCount As Integer
Dim initialLineCount As Integer Dim initialLineCount As Integer
Dim lineLen As Integer Dim lineLen As Integer
Dim mathExpect As Integer
Dim minLastLineLength As Integer Dim minLastLineLength As Integer
paraLen = 0 Dim medianLen As Integer
lineLen = 0 Dim paraLines() As Object
minLastLineLength = 0 Dim decreaseKerningFailed As Boolean
initialLineCount = 0 Dim increaseKerningFailed As Boolean
Dim fallBackSuccess As Boolean
fallBackSuccess = false
decreaseKerningFailed = false
increaseKerningFailed = false
oViewCursor = ThisComponent.CurrentController.getViewCursor() oViewCursor = ThisComponent.CurrentController.getViewCursor()
oViewCursor.goToRange(targetPara, false) oViewCursor.goToRange(targetPara, false)
oTextCursor = oViewCursor.Text.createTextCursorByRange(oViewCursor) oTextCursor = oViewCursor.Text.createTextCursorByRange(oViewCursor)
oPara = oViewCursor.Text.createTextCursorByRange(oViewCursor)
&apos;Go to start of para
oTextCursor.gotoStartOfParagraph(false)
&apos;Get start position
oParaStart = oTextCursor.getStart()
&apos;Go to end of para
oTextCursor.gotoEndOfParagraph(false)
&apos;Get end position
oParaEnd = oTextCursor.getEnd()
&apos;return Text cursor to start
oTextCursor.goToRange(oParaStart,false)
&apos;oPara is full para cursor
oPara.goToRange(oParaStart,false)
oPara.goToRange(oParaEnd,true)
Do oParaStart = getParaStart(oTextCursor)
&apos;Not first iteration oParaEnd = getParaEnd(oTextCursor)
If minLastLineLength &lt;&gt; 0 Then oPara = getParaSelected(oParaStart,oParaEnd)
If oPara.CharKerning &lt; 50 Then paraLen = Len(oPara.String)
If(IsEmpty(oPara.CharKerning)) Then paraLines = getParaLines(oPara)
oPara.CharKerning = 0 initialLineCount = getParaLinesCount(paraLines)
lineLen = getParaLineLength(paraLines, 0)
medianLen = calculateMedianParaLen(oPara)
minLastLineLength = medianLen * 0.89
If Not IsEmpty(oPara.CharKerning) Then
initialCharKerning = oPara.CharKerning
Else Else
oPara.CharKerning = oPara.CharKerning + 2 initialCharKerning = 0
End If End If
Else
&apos;Failed to balance para If initialLineCount &lt; 2 Then
Exit sub
EndIf
Do While lastLineIsNotBalanced(lineLen, minLastLineLength) And Not (decreaseKerningFailed And increaseKerningFailed)
If NOT decreaseKerningFailed Then
decreaseCharKerning(oPara)
EndIf
If decreaseKerningFailed AND NOT increaseKerningFailed Then
increaseCharKerning(oPara)
EndIf
paraLines = getParaLines(oPara)
lineCount = getParaLinesCount(paraLines)
lineLen = getParaLineLength(paraLines,0)
If (lineCount &gt; initialLineCount) Then
MsgBox oPara.CharKerning
increaseKerningFailed = true
oPara.CharKerning = initialCharKerning
EndIf
If (lineCount = initialLineCount - 1 ) Then
&apos;Tightened last line but it is still smaller than we need
decreaseKerningFailed = true
fallBackSuccess = tryExpandPrevLine(oPara, minLastLineLength)
If fallBackSuccess Then
Exit Sub Exit Sub
EndIf EndIf
&apos;Fall back to initial values
MsgBox oPara.CharKerning
oPara.CharKerning = initialCharKerning
EndIf
If (oPara.CharKerning &gt; 50) Then
MsgBox oPara.CharKerning
increaseKerningFailed = true
oPara.CharKerning = initialCharKerning
EndIf
If (oPara.CharKerning &lt; -15) Then
decreaseKerningFailed = true
MsgBox oPara.CharKerning
oPara.CharKerning = initialCharKerning
EndIf
Loop
MsgBox oPara.CharKerning
End Sub
Function tryExpandPrevLine(oPara As Object, minLastLineLength As Integer) As Boolean
Dim lineCount As Integer
Dim initialLineCount As Integer
paraLines = getParaLines(oPara)
lineLen = getParaLineLength(paraLines,0)
initialLineCount = getParaLinesCount(paraLines)
lineCount = initialLineCount
Do While lineCount = initialLineCount And lastLineIsNotBalanced(lineLen, minLastLineLength)
increaseCharKerning(paraLines(UBound(paraLines)- 1))
paraLines = getParaLines(oPara)
lineCount = getParaLinesCount(paraLines)
lineLen = getParaLineLength(paraLines,0)
Loop
If Not lastLineIsNotBalanced(lineLen, minLastLineLength) And lineCount = initialLineCount Then
tryExpandPrevLine = true
MsgBox paraLines(UBound(paraLines)- 1).CharKerning
Else
tryExpandPrevLine = false
EndIf
End Function
Function getParaLinesCount(paraLines() As Object) As Integer
getParaLinesCount = UBound(paraLines) + 1
End Function
Function getParaLineLength(paraLines() As Object, lineNumber As Integer) As Integer
Dim arrIndex As Integer
arrIndex = UBound(paraLines) - lineNumber
If (arrIndex &gt;= 0) Then
getParaLineLength = Len(paraLines(arrIndex).String)
Else
&apos;Throw an error?
getParaLineLength = 0
EndIf EndIf
oViewCursor.goToRange(oParaStart,false) End Function
oTextCursor.goToRange(oParaStart,false)
lineCount = 0 Function getParaLines(oPara As Object) As Variant
Dim oTextCursor As Object
Dim oViewCursor As Object
Dim paraLine As Object
Dim paraLines() As Object
oViewCursor = ThisComponent.CurrentController.getViewCursor()
&apos;initial value is 1 As paragraph can&apos;t be 0 lines long
oTextCursor = oPara.Text.createTextCursorByRange(oPara)
oTextCursor.collapseToStart()
oViewCursor.goToRange(oTextCursor,false)
While NOT oTextCursor.isEndOfParagraph() While NOT oTextCursor.isEndOfParagraph()
oViewCursor.gotoEndOfLine(true) oViewCursor.gotoEndOfLine(true)
oTextCursor = oViewCursor.Text.createTextCursorByRange(oViewCursor) paraLine = oViewCursor.Text.createTextCursorByRange(oViewCursor)
lineLen = Len(oTextCursor.getString()) AddToArray(paraLines, paraLine)
paraLen = paraLen + lineLen
lineCount = lineCount + 1
oViewCursor.collapseToEnd() oViewCursor.collapseToEnd()
oTextCursor.goToRange(oViewCursor,false)
Wend Wend
&apos;set initial line count getParaLines = paraLines
If initialLineCount = 0 Then End Function
initialLineCount = lineCount
ElseIf lineCount &gt; initialLineCount Then
&apos;Undo last iteration as line overflow happened. Sub decreaseCharKerning(oPara As Object)
&apos;And exit
If(IsEmpty(oPara.CharKerning)) Then If(IsEmpty(oPara.CharKerning)) Then
oPara.CharKerning = 0 oPara.CharKerning = 0
Else Else
oPara.CharKerning = oPara.CharKerning - 2 oPara.CharKerning = oPara.CharKerning - 2
End If End If
Exit sub
EndIf
mathExpect = paraLen / lineCount
minLastLineLength = mathExpect * 0.9
Loop Until minLastLineLength &lt; lineLen
End Sub End Sub
Sub increaseCharKerning(oPara As Object)
If(IsEmpty(oPara.CharKerning)) Then
oPara.CharKerning = 0
Else
oPara.CharKerning = oPara.CharKerning + 2
End If
End Sub
Function lastLineIsNotBalanced(lineLen As Integer,minLastLineLength As Integer) As Boolean
lastLineIsNotBalanced = true
If lineLen = 0 Then
lastLineIsNotBalanced = false
Exit Function
EndIf
If lineLen &gt;= minLastLineLength Then
lastLineIsNotBalanced = false
EndIf
End Function
Function getParaStart(oTextCursor As Object) As Object
If NOT oTextCursor.isStartOfParagraph() Then
oTextCursor.gotoStartOfParagraph(false)
EndIf
getParaStart = oTextCursor.getStart()
End Function
Function getParaEnd(oTextCursor As Object) As Object
If NOT oTextCursor.isEndOfParagraph() Then
oTextCursor.gotoEndOfParagraph(false)
EndIf
getParaEnd = oTextCursor.getEnd()
End Function
Function getParaSelected(oParaStart As Object,oParaEnd As Object) As Object
Dim oPara As Object
oPara = oParaStart.Text.createTextCursorByRange(oParaStart)
oPara.goToRange(oParaEnd,true)
getParaSelected = oPara
End Function
Function calculateMedianParaLen(oPara As Object) As Integer
Dim oTextCursor As Object
Dim oViewCursor As Object
Dim lineCount As Integer
Dim lineLen As Integer
Dim linesLen As Integer
linesLen = 0
calculateMedianParaLen = 0
lineCount = 0
lineLen = 0
oViewCursor = ThisComponent.CurrentController.getViewCursor()
oViewCursor.goToRange(oPara, false)
oViewCursor.collapseToStart()
oTextCursor = oViewCursor.Text.createTextCursorByRange(oViewCursor)
oParaStart = getParaStart(oTextCursor)
oViewCursor.goToRange(oParaStart,false)
&apos;Select first line
oViewCursor.gotoEndOfLine(true)
While NOT oTextCursor.isEndOfParagraph()
lineLen = Len(oViewCursor.getString())
linesLen = linesLen + lineLen
lineCount = lineCount + 1
oViewCursor.collapseToEnd()
oViewCursor.gotoEndOfLine(true)
oTextCursor.goToRange(oViewCursor,false)
Wend
If lineCount &gt; 0 Then
calculateMedianParaLen = linesLen / lineCount
EndIf
End Function
Sub convertBookmarksToFootnotes() Sub convertBookmarksToFootnotes()
Dim description As String Dim description As String

View file

@ -362,7 +362,7 @@ Sub setUniqPageStylesDEPRECATED
End Sub End Sub
Function hasPageStyleWith(pageStyleName) Function hasPageStyleWith(pageStyleName As String) As Boolean
Dim enum1 As Object Dim enum1 As Object
Dim enum1Element As Object Dim enum1Element As Object
Dim curPage As String Dim curPage As String
@ -387,7 +387,7 @@ Function hasPageStyleWith(pageStyleName)
hasPageStyleWith = false hasPageStyleWith = false
End Function End Function
Function findFirstPageNumberWithStyle(pageStyleName) Function findFirstPageNumberWithStyle(pageStyleName As String) As Integer
Dim enum1 As Object Dim enum1 As Object
Dim enum1Element As Object Dim enum1Element As Object
Dim curPage As String Dim curPage As String
@ -396,6 +396,7 @@ Function findFirstPageNumberWithStyle(pageStyleName)
Dim oViewCursor As Object Dim oViewCursor As Object
Dim anchor As Object Dim anchor As Object
Dim oSavePosition As Object Dim oSavePosition As Object
Dim curPageStyleName As String
oViewCursor = ThisComponent.CurrentController.getViewCursor() oViewCursor = ThisComponent.CurrentController.getViewCursor()
oSavePosition = oViewCursor.Text.createTextCursorByRange(oViewCursor) oSavePosition = oViewCursor.Text.createTextCursorByRange(oViewCursor)
enum1 = ThisComponent.Text.createEnumeration() enum1 = ThisComponent.Text.createEnumeration()