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"?>
<!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
@ -441,10 +441,27 @@ Sub stretchPrevPage()
oViewCursor.goToRange(oSavePosition,false)
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)
anchor.ParaAdjust = 2
&apos;anchor.ParaLastLineAdjust = 2
anchor.ParaLastLineAdjust = 2
balancePara(anchor)
End Sub
@ -478,77 +495,221 @@ Sub balancePara(targetPara As Object)
Dim lineCount As Integer
Dim initialLineCount As Integer
Dim lineLen As Integer
Dim mathExpect As Integer
Dim minLastLineLength As Integer
paraLen = 0
lineLen = 0
minLastLineLength = 0
initialLineCount = 0
Dim medianLen As Integer
Dim paraLines() As Object
Dim decreaseKerningFailed As Boolean
Dim increaseKerningFailed As Boolean
Dim fallBackSuccess As Boolean
fallBackSuccess = false
decreaseKerningFailed = false
increaseKerningFailed = false
oViewCursor = ThisComponent.CurrentController.getViewCursor()
oViewCursor.goToRange(targetPara, false)
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
&apos;Not first iteration
If minLastLineLength &lt;&gt; 0 Then
If oPara.CharKerning &lt; 50 Then
If(IsEmpty(oPara.CharKerning)) Then
oPara.CharKerning = 0
Else
oPara.CharKerning = oPara.CharKerning + 2
End If
Else
&apos;Failed to balance para
oParaStart = getParaStart(oTextCursor)
oParaEnd = getParaEnd(oTextCursor)
oPara = getParaSelected(oParaStart,oParaEnd)
paraLen = Len(oPara.String)
paraLines = getParaLines(oPara)
initialLineCount = getParaLinesCount(paraLines)
lineLen = getParaLineLength(paraLines, 0)
medianLen = calculateMedianParaLen(oPara)
minLastLineLength = medianLen * 0.89
If Not IsEmpty(oPara.CharKerning) Then
initialCharKerning = oPara.CharKerning
Else
initialCharKerning = 0
End If
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
EndIf
&apos;Fall back to initial values
MsgBox oPara.CharKerning
oPara.CharKerning = initialCharKerning
EndIf
oViewCursor.goToRange(oParaStart,false)
oTextCursor.goToRange(oParaStart,false)
lineCount = 0
While NOT oTextCursor.isEndOfParagraph()
oViewCursor.gotoEndOfLine(true)
oTextCursor = oViewCursor.Text.createTextCursorByRange(oViewCursor)
lineLen = Len(oTextCursor.getString())
paraLen = paraLen + lineLen
lineCount = lineCount + 1
oViewCursor.collapseToEnd()
Wend
&apos;set initial line count
If initialLineCount = 0 Then
initialLineCount = lineCount
ElseIf lineCount &gt; initialLineCount Then
&apos;Undo last iteration as line overflow happened.
&apos;And exit
If(IsEmpty(oPara.CharKerning)) Then
oPara.CharKerning = 0
Else
oPara.CharKerning = oPara.CharKerning - 2
End If
Exit sub
If (oPara.CharKerning &gt; 50) Then
MsgBox oPara.CharKerning
increaseKerningFailed = true
oPara.CharKerning = initialCharKerning
EndIf
mathExpect = paraLen / lineCount
minLastLineLength = mathExpect * 0.9
Loop Until minLastLineLength &lt; lineLen
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
End Function
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()
oViewCursor.gotoEndOfLine(true)
paraLine = oViewCursor.Text.createTextCursorByRange(oViewCursor)
AddToArray(paraLines, paraLine)
oViewCursor.collapseToEnd()
oTextCursor.goToRange(oViewCursor,false)
Wend
getParaLines = paraLines
End Function
Sub decreaseCharKerning(oPara As Object)
If(IsEmpty(oPara.CharKerning)) Then
oPara.CharKerning = 0
Else
oPara.CharKerning = oPara.CharKerning - 2
End If
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()
Dim description As String

View file

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