//////////////////////////////////////////////////////////////////////////////// // EndProcessingInstruction // bool XmlWriter::EndProcessingInstruction() { mbSimpleElement = false; switch (mnState) { case kStateProcessingInstruction: mnState = kStateChars; return WriteText( "?>", 2 ); case kStateElement: EA_FAIL_MESSAGE( "XmlWriter: Cannot close processing instruction because we are in an element." ); mnState = kStateChars; return false; case kStateChars: EA_FAIL_MESSAGE( "XmlWriter: Cannot close processing instruction because it was already closed." ); mnState = kStateChars; return false; case kStateCDATA: EA_FAIL_MESSAGE( "XmlWriter: Cannot close processing instruction because we are in a CDATA section." ); return false; } return false; }
bool XmlWriter::WriteCDATA( const char16_t *psCharData, size_t nCount ) { // Verify that there is no "]]>" sequence in the input text. #if (defined(EA_TRACE_ENABLED) && EA_TRACE_ENABLED) || defined(EA_ASSERT_ENABLED) // If the EATrace or EAAssert packages are configured to enable assertions... // We can't use a built-in function such as strstr because our text might not // be 0-terminated. We could however use the STL find algorithm. const size_t nStrlen = ((nCount == kSizeTypeNull) ? wcslen(psCharData) : nCount); const size_t nStrlenToCheck = ((nStrlen > 2) ? (nStrlen - 2) : 0); for(size_t i = 0; i < nStrlenToCheck; ++i) { if((psCharData[i] == ']') && (psCharData[i + 1] == ']') && (psCharData[i + 2] == '>')) { EA_FAIL_MESSAGE("XmlWriter: User-specified CDATA has embedded ]]> sequence."); break; } } #endif if (mnState != kStateCDATA) { if (!CloseCurrentElement()) return false; if (!WriteText( "<![CDATA[", 9 )) return false; mnState = kStateCDATA; } return WriteText( psCharData, nCount ); }
//////////////////////////////////////////////////////////////////////////////// // EndElement // bool XmlWriter::EndElement( const char *psElementName ) { EA_ASSERT(mnIndentLevel > 0); mnIndentLevel--; switch (mnState) { case kStateProcessingInstruction: EA_FAIL_MESSAGE( "XmlWriter: Cannot close element because we are in a processing instruction." ); return false; case kStateElement: mnState = kStateChars; mbSimpleElement = false; return WriteText( "/>", 2 ); case kStateCDATA: CloseCurrentElement(); // Fall through. case kStateChars: if (!mbSimpleElement ) { // If the current element has no child elements... if (!WriteIndent() ) // Then write an indent before writing the element end. return false; } mbSimpleElement = false; return ( WriteText( "</", 2 ) && WriteText( psElementName, kSizeTypeNull ) && WriteText( ">", 1 ) ); } return false; }
/////////////////////////////////////////////////////////////////////////////// // AppendHangulCharCluster // eastl_size_t Typesetter::AppendHangulCharCluster(eastl_size_t iCharBegin, eastl_size_t charCount, const Char* pCharCluster, eastl_size_t clusterSize, int clusterType) { // The 'iCharBegin' argument refers to the position of pCharCluster in mLineLayout.mCharArray. // There is a possibility that pCharCluster doesn't point to mLineLayout.mCharArray[iCharBegin], // as we may be doing some kind of implicit substitution. Thus we have pCharCluster // as an explicit parameter. const AnalysisInfo* const pAnalysisInfo = &mLineLayout.mAnalysisInfoArray[iCharBegin]; GlyphId pGlyphIdArray[kMaxHangulGlyphClusterSize]; eastl_size_t glyphCount = 0; eastl_size_t charsEaten = 0; // Number of chars read from pCharCluster. EA_ASSERT(clusterSize && ((iCharBegin + charCount) <= mLineLayout.mCharArray.size())); #ifdef EA_DEBUG memset(pGlyphIdArray, 0, sizeof(pGlyphIdArray)); #endif switch(clusterType) { case kHangulClusterTypeJamo: { const Char cTone = pCharCluster[clusterSize - 1]; const bool bAppendTone = IsTone(cTone); int syllableLength; Char c; if(bAppendTone) --clusterSize; // Pretend it isn't there for now. if((clusterSize >= 3) && IsLSyllable(pCharCluster[0]) && IsVSyllable(pCharCluster[1]) && IsTSyllable(pCharCluster[2])) syllableLength = 3; else if((clusterSize >= 2) && IsLSyllable(pCharCluster[0]) && IsVSyllable(pCharCluster[1])) syllableLength = 2; else syllableLength = 0; if(syllableLength) { if(syllableLength == 3) c = GetSyllableLVT(pCharCluster[0], pCharCluster[1], pCharCluster[2]); else c = GetSyllableLV(pCharCluster[0], pCharCluster[1]); GetGlyphsForChar(&c, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount); charsEaten += syllableLength; } // If there are any other chars to shape (usually there aren't), just append them. for(eastl_size_t i = charsEaten; i < clusterSize; i += charsEaten) { if((pCharCluster[i] != kJamoLFiller) && // Outright ignore filler chars. (pCharCluster[i] != kJamoVFiller)) { // The font selection in use had better have the desired glyphs or // else we will be displaying a lot of square boxes on the screen. charsEaten += GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount); } else ++charsEaten; } EA_ASSERT(glyphCount > 0); // Do we have just a single Jamo filler char? if(glyphCount == 0) { const Char cHangulFiller = 0x3164; // 0x3164 is the Hangul filler char. It's just blank like a space char. charsEaten += GetGlyphsForChar(&cHangulFiller, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount, L"\x25CB _o", 4); } if(bAppendTone) { charsEaten += GetGlyphsForChar(&cTone, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount, (cTone == kHangulTone1) ? L"\x00b7" : L":", 1); } break; } case kHangulClusterTypeTone: // Standalone tone with no preceeding base glyph. { // We prepend a character which is a circle implemented with dotted lines. // It is the Unicode standard for generic base character to be represented // by such a dotted circle. It is a defacto standard that we prepend such // a character when none is provided. It makes the text look more sensible. const Char cDottedCircle = 0x25CC; for(eastl_size_t i = charsEaten; i < clusterSize; i += charsEaten) // clusterSize should usually (always?) be just one. { // Note that in practice we're going to need to put the tone to the // left of the glyph, though here we stuff it afterwards. What we have // here won't do. Also, the tone chars ideally have a zero advance, // but the fallbacks definitely do not. // We draw the tone, using fallback characters if the tone char isn't present. charsEaten += GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount, (pCharCluster[i] == kHangulTone1) ? L"\x00b7" : L":", 1); // Append a dotted-circle glyph, with a fallback of some other glyphs. GetGlyphsForChar(&cDottedCircle, 1, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount, L"\x25CB _o", 4); } break; } case kHangulClusterTypeUnicode: { // We just convert the Unicode Chars to glyphs. for(eastl_size_t i = charsEaten; i < clusterSize; i += charsEaten) { charsEaten += GetGlyphsForChar(pCharCluster + i, clusterSize - i, pAnalysisInfo, pGlyphIdArray + glyphCount, glyphCount); } break; } default: EA_FAIL_MESSAGE("Typesetter::AppendHangulCharCluster: Unknown cluster type."); break; } // Assert that all of the passed in cluster was processed. EA_ASSERT(charsEaten == clusterSize); // We use the general glyph append function. AppendGeneralGlyphCluster(iCharBegin, charCount, pCharCluster, charsEaten, pGlyphIdArray, glyphCount, pAnalysisInfo->mnBidiLevel); // We use the general glyph placement function. PlaceGeneralGlyphCluster(iCharBegin, charsEaten); // As it stands now, all chars must result in at least one glyph, though that // one glyph could be a zero-width space character. Note that the render code // has the opportunity to remove such a "no-op" instruction from the display list. EA_ASSERT(glyphCount > 0); return glyphCount; }