blob: d5006957bd9babaa58a041a7a1b36723497153d2 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.ui.text
import androidx.compose.ui.text.AnnotatedString.Range
import androidx.compose.ui.util.fastFold
import androidx.compose.ui.util.fastMap
import java.util.SortedSet
/**
* The core function of [AnnotatedString] transformation.
*
* @param transform the transformation method
* @return newly allocated transformed AnnotatedString
*/
internal actual fun AnnotatedString.transform(
transform: (String, Int, Int) -> String
): AnnotatedString {
val transitions = sortedSetOf(0, text.length)
collectRangeTransitions(spanStylesOrNull, transitions)
collectRangeTransitions(paragraphStylesOrNull, transitions)
collectRangeTransitions(annotations, transitions)
var resultStr = ""
val offsetMap = mutableMapOf(0 to 0)
transitions.windowed(size = 2) { (start, end) ->
resultStr += transform(text, start, end)
offsetMap.put(end, resultStr.length)
}
val newSpanStyles = spanStylesOrNull?.fastMap {
// The offset map must have mapping entry from all style start, end position.
Range(it.item, offsetMap[it.start]!!, offsetMap[it.end]!!)
}
val newParaStyles = paragraphStylesOrNull?.fastMap {
Range(it.item, offsetMap[it.start]!!, offsetMap[it.end]!!)
}
val newAnnotations = annotations?.fastMap {
Range(it.item, offsetMap[it.start]!!, offsetMap[it.end]!!)
}
return AnnotatedString(
text = resultStr,
spanStylesOrNull = newSpanStyles,
paragraphStylesOrNull = newParaStyles,
annotations = newAnnotations
)
}
/**
* Adds all [AnnotatedString.Range] transition points
*
* @param ranges The list of AnnotatedString.Range
* @param target The output list
*/
private fun collectRangeTransitions(
ranges: List<Range<*>>?,
target: SortedSet<Int>
) {
ranges?.fastFold(target) { acc, range ->
acc.apply {
add(range.start)
add(range.end)
}
}
}