// Generate new items inheriting properties from the previous public MHTextItem NewItem() { MHTextItem pItem = new MHTextItem(); pItem.m_Colour = m_Colour; return(pItem); }
// UK MHEG specifies the use of the Tiresias font and broadcasters appear to // assume that all MHEG applications will lay the text out in the same way. // Recreate the image. protected void Redraw() { if (!RunningStatus || m_pDisplay == null) { return; } if (m_nBoxWidth == 0 || m_nBoxHeight == 0) { return; // Can't draw zero sized boxes. } m_pDisplay.SetSize(m_nBoxWidth, m_nBoxHeight); m_pDisplay.Clear(); MHRgba textColour = GetColour(m_textColour); // Process any escapes in the text and construct the text arrays. MHSequence <MHTextLine> theText = new MHSequence <MHTextLine>(); // Set up the first item on the first line. MHTextItem pCurrItem = new MHTextItem(); MHTextLine pCurrLine = new MHTextLine(); pCurrLine.Items.Append(pCurrItem); theText.Append(pCurrLine); Stack <MHRgba> m_ColourStack = new Stack <MHRgba>(); // Stack to handle nested colour codes. m_ColourStack.Push(textColour); pCurrItem.Colour = textColour; int i = 0; while (i < m_Content.Size) { char ch = m_Content.GetAt(i++); if (ch == '\t') // Tab - start a new item if we have any text in the existing one. { if (pCurrItem.Text.Size != 0) { pCurrItem = pCurrItem.NewItem(); pCurrLine.Items.Append(pCurrItem); } pCurrItem.TabCount++; } else if (ch == '\r') // CR - line break. // TODO: Two CRs next to one another are treated as </P> rather than <BR><BR> // This should also include the sequence CRLFCRLF. { pCurrLine = new MHTextLine(); theText.Append(pCurrLine); pCurrItem = pCurrItem.NewItem(); pCurrLine.Items.Append(pCurrItem); } else if (ch == 0x1b) // Escape - special codes. { if (i == m_Content.Size) { break; } char code = m_Content.GetAt(i); // The only codes we are interested in are the start and end of colour. // TODO: We may also need "bold" and some hypertext colours. if (code >= 0x40 && code <= 0x5e) // Start code // Start codes are followed by a parameter count and a number of parameter bytes. { if (++i == m_Content.Size) { break; } char paramCount = m_Content.GetAt(i); i++; if (code == 0x43 && paramCount == 4 && i + paramCount <= m_Content.Size) { // Start of colour. if (pCurrItem.Text.Size != 0) { pCurrItem = pCurrItem.NewItem(); pCurrLine.Items.Append(pCurrItem); } pCurrItem.Colour = new MHRgba(m_Content.GetAt(i), m_Content.GetAt(i + 1), m_Content.GetAt(i + 2), 255 - m_Content.GetAt(i + 3)); // Push this colour onto the colour stack. m_ColourStack.Push(pCurrItem.Colour); } else { Logging.Log(Logging.MHLogWarning, "Unknown text escape code " + code); } i += paramCount; // Skip the parameters } else if (code >= 0x60 && code <= 0x7e) // End code. { i++; if (code == 0x63) { if (m_ColourStack.Count > 1) { m_ColourStack.Pop(); // Start a new item since we're using a new colour. if (pCurrItem.Text.Size != 0) { pCurrItem = pCurrItem.NewItem(); pCurrLine.Items.Append(pCurrItem); } // Set the subsequent text in the colour we're using now. pCurrItem.Colour = m_ColourStack.Peek(); } } } } else if (ch <= 0x1f) { // Certain characters including LF and the marker codes between 0x1c and 0x1f are // explicitly intended to be ignored. Include all the other codes. } else // Add to the current text. { int nStart = i - 1; while (i < m_Content.Size && m_Content.GetAt(i) >= 0x20) { i++; } pCurrItem.Text.Append(new MHOctetString(m_Content, nStart, i - nStart)); } } // Set up the initial attributes. int style, size, lineSpace, letterSpace; InterpretAttributes(m_fontAttrs, out style, out size, out lineSpace, out letterSpace); // Create a font with this information. m_pDisplay.SetFont(size, (style & 2) != 0, (style & 1) != 0); // Calculate the layout of each section. for (i = 0; i < theText.Size; i++) { MHTextLine pLine = theText.GetAt(i); pLine.LineWidth = 0; for (int j = 0; j < pLine.Items.Size; j++) { MHTextItem pItem = pLine.Items.GetAt(j); // Set any tabs. for (int k = 0; k < pItem.TabCount; k++) { pLine.LineWidth += TABSTOP - pLine.LineWidth % TABSTOP; } if (pItem.UnicodeLength == 0) { // Convert UTF-8 to Unicode. int s = pItem.Text.Size; pItem.Unicode = pItem.Text.ToString(); pItem.UnicodeLength = pItem.Unicode.Length; } // Fit the text onto the line. int nFullText = pItem.UnicodeLength; // Get the box size and update pItem.m_nUnicode to the number that will fit. Rectangle rect = m_pDisplay.GetBounds(pItem.Unicode, ref nFullText, m_nBoxWidth - pLine.LineWidth); if (nFullText == pItem.UnicodeLength || !m_fTextWrap) { // All the characters fit or we're not wrapping. pItem.Width = rect.Width; pLine.LineWidth += rect.Width; } /* else if (m_fTextWrap) * { // No, we have to word-wrap. * int nTruncated = pItem.UnicodeLength; // Just in case. * // Now remove characters until we find a word-break character. * while (pItem.UnicodeLength > 0 && pItem.Unicode[pItem.UnicodeLength] != ' ') pItem.UnicodeLength--; * // If there are now word-break characters we truncate the text. * if (pItem.UnicodeLength == 0) pItem.UnicodeLength = nTruncated; * // Special case to avoid infinite loop if the box is very narrow. * if (pItem.UnicodeLength == 0) pItem.UnicodeLength = 1; * * // We need to move the text we've cut off this line into a new line. * int nNewWidth = nFullText - pItem.UnicodeLength; * int nNewStart = pItem.UnicodeLength; * // Remove any spaces at the start of the new section. * while (nNewWidth != 0 && pItem.Unicode[nNewStart] == ' ') { nNewStart++; nNewWidth--; } * if (nNewWidth != 0) { * // Create a new line from the extra text. * MHTextLine pNewLine = new MHTextLine(); * theText.InsertAt(pNewLine, i+1); * // The first item on the new line is the rest of the text. * MHTextItem pNewItem = pItem.NewItem(); * pNewLine.Items.Append(pNewItem); * pNewItem.Unicode = pItem.Unicode.Substring(nNewStart, nNewWidth); * pNewItem.UnicodeLength = nNewWidth; * } * // Remove any spaces at the end of the old section. If we don't do that and * // we are centering or right aligning the text we'll get it wrong. * while (pItem.UnicodeLength > 1 && pItem.Unicode[pItem.UnicodeLength - 1] == ' ') pItem.UnicodeLength--; * int uniLength = pItem.UnicodeLength; * rect = m_pDisplay.GetBounds(pItem.Unicode, ref uniLength, 0); * pItem.Width = rect.Width; * pLine.LineWidth += rect.Width; * } */} } // Now output the text. int yOffset = 0; // If there isn't space for all the lines we should drop extra lines. int nNumLines = theText.Size; do { if (m_VertJ == End) { yOffset = m_nBoxHeight - nNumLines * lineSpace; } else if (m_VertJ == Centre) { yOffset = (m_nBoxHeight - nNumLines * lineSpace) / 2; } if (yOffset < 0) { nNumLines--; } } while (yOffset < 0); for (i = 0; i < nNumLines; i++) { MHTextLine pLine = theText.GetAt(i); int xOffset = 0; if (m_HorizJ == End) { xOffset = m_nBoxWidth - pLine.LineWidth; } else if (m_HorizJ == Centre) { xOffset = (m_nBoxWidth - pLine.LineWidth) / 2; } //ASSERT(xOffset >= 0); for (int j = 0; j < pLine.Items.Size; j++) { MHTextItem pItem = pLine.Items.GetAt(j); // Tab across if necessary. for (int k = 0; k < pItem.TabCount; k++) { xOffset += TABSTOP - xOffset % TABSTOP; } if (pItem.Unicode.Length != 0) // We may have blank lines. { m_pDisplay.AddText(xOffset, yOffset, // Jas removed this cos it doesn't make sense yOffset + lineSpace pItem.Unicode.Substring(0, pItem.UnicodeLength), pItem.Colour); } xOffset += pItem.Width; } yOffset += lineSpace; if (yOffset + lineSpace > m_nBoxHeight) { break; } } }