package braille import ( "errors" "unicode/utf8" ) // displayMasks is shared by the BrlAPI writer and cell export. A zero AND mask // makes a Unicode Braille cell independent of BRLTTY's text translation table. // Dots are attributes to OR into the cell, not a replacement cell array. func displayMasks(text string, dots []byte) ([]byte, []byte, error) { if !utf8.ValidString(text) { return nil, nil, errors.New("invalid braille text") } length := utf8.RuneCountInString(text) if len(dots) != 0 && len(dots) != length { return nil, nil, errors.New("invalid braille indicator length") } andMask, orMask := make([]byte, length), make([]byte, length) for index, cell := range []rune(text) { andMask[index] = 0xff if len(dots) != 0 { orMask[index] = dots[index] } if cell >= 0x2800 && cell <= 0x28ff { andMask[index] = 0 orMask[index] |= byte(cell - 0x2800) } } return andMask, orMask, nil } // rawCells exports a translated viewport without opening a display. It shares // the physical writer's cell/attribute handling and the existing viewport's // translation, wrapping and routing maps. The caller owns this viewport and // serializes all access, independently of any physical viewport. // // Ordinary text needs BRLTTY translation and is deliberately rejected. Callers // must first use the existing liblouis path with an explicitly chosen table. // Spaces here are blank padding or the synthetic end-of-line cursor cell. // cursorDots is an explicit, static overlay; this does not reproduce BRLTTY's // configured cursor shape or blink timing. No native routing metadata is exported. func (v *viewport) rawCells(cursorDots byte) ([]byte, error) { if _, err := (Geometry{Columns: v.width, Rows: 1}).Cells(); err != nil { return nil, err } text := []rune(v.frame()) for index, cell := range text { if cell == ' ' { text[index] = '\u2800' } else if cell < 0x2800 || cell > 0x28ff { return nil, errors.New("raw braille export requires translated cells") } } _, cells, err := displayMasks(string(text), v.displayDots()) if err != nil { return nil, err } if cursor := v.displayCursor(); cursor > 0 { cells[cursor-1] |= cursorDots } return cells, nil }