wxArrayString wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid, wxDC& dc, const wxGridCellAttr& attr, const wxRect& rect, int row, int col) { dc.SetFont(attr.GetFont()); const wxCoord maxWidth = rect.GetWidth(); // Transform logical lines into physical ones, wrapping the longer ones. const wxArrayString logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0'); wxArrayString physicalLines; for ( wxArrayString::const_iterator it = logicalLines.begin(); it != logicalLines.end(); ++it ) { const wxString& line = *it; if ( dc.GetTextExtent(line).x > maxWidth ) { // Line does not fit, break it up. BreakLine(dc, line, maxWidth, physicalLines); } else // The entire line fits as is { physicalLines.push_back(line); } } return physicalLines; }
nsresult InternetCiter::Rewrap(const nsAString& aInString, uint32_t aWrapCol, uint32_t aFirstLineOffset, bool aRespectNewlines, nsAString& aOutString) { // There shouldn't be returns in this string, only dom newlines. // Check to make sure: #ifdef DEBUG int32_t cr = aInString.FindChar(char16_t('\r')); NS_ASSERTION((cr < 0), "Rewrap: CR in string gotten from DOM!\n"); #endif /* DEBUG */ aOutString.Truncate(); nsresult rv; RefPtr<mozilla::intl::LineBreaker> lineBreaker = mozilla::intl::LineBreaker::Create(); MOZ_ASSERT(lineBreaker); // Loop over lines in the input string, rewrapping each one. uint32_t length; uint32_t posInString = 0; uint32_t outStringCol = 0; uint32_t citeLevel = 0; const nsPromiseFlatString &tString = PromiseFlatString(aInString); length = tString.Length(); while (posInString < length) { // Get the new cite level here since we're at the beginning of a line uint32_t newCiteLevel = 0; while (posInString < length && tString[posInString] == gt) { ++newCiteLevel; ++posInString; while (posInString < length && tString[posInString] == space) { ++posInString; } } if (posInString >= length) { break; } // Special case: if this is a blank line, maintain a blank line // (retain the original paragraph breaks) if (tString[posInString] == nl && !aOutString.IsEmpty()) { if (aOutString.Last() != nl) { aOutString.Append(nl); } AddCite(aOutString, newCiteLevel); aOutString.Append(nl); ++posInString; outStringCol = 0; continue; } // If the cite level has changed, then start a new line with the // new cite level (but if we're at the beginning of the string, // don't bother). if (newCiteLevel != citeLevel && posInString > newCiteLevel+1 && outStringCol) { BreakLine(aOutString, outStringCol, 0); } citeLevel = newCiteLevel; // Prepend the quote level to the out string if appropriate if (!outStringCol) { AddCite(aOutString, citeLevel); outStringCol = citeLevel + (citeLevel ? 1 : 0); } // If it's not a cite, and we're not at the beginning of a line in // the output string, add a space to separate new text from the // previous text. else if (outStringCol > citeLevel) { aOutString.Append(space); ++outStringCol; } // find the next newline -- don't want to go farther than that int32_t nextNewline = tString.FindChar(nl, posInString); if (nextNewline < 0) { nextNewline = length; } // For now, don't wrap unquoted lines at all. // This is because the plaintext edit window has already wrapped them // by the time we get them for rewrap, yet when we call the line // breaker, it will refuse to break backwards, and we'll end up // with a line that's too long and gets displayed as a lone word // on a line by itself. Need special logic to detect this case // and break it ourselves without resorting to the line breaker. if (!citeLevel) { aOutString.Append(Substring(tString, posInString, nextNewline-posInString)); outStringCol += nextNewline - posInString; if (nextNewline != (int32_t)length) { aOutString.Append(nl); outStringCol = 0; } posInString = nextNewline+1; continue; } // Otherwise we have to use the line breaker and loop // over this line of the input string to get all of it: while ((int32_t)posInString < nextNewline) { // Skip over initial spaces: while ((int32_t)posInString < nextNewline && nsCRT::IsAsciiSpace(tString[posInString])) { ++posInString; } // If this is a short line, just append it and continue: if (outStringCol + nextNewline - posInString <= aWrapCol-citeLevel-1) { // If this short line is the final one in the in string, // then we need to include the final newline, if any: if (nextNewline+1 == (int32_t)length && tString[nextNewline-1] == nl) { ++nextNewline; } // Trim trailing spaces: int32_t lastRealChar = nextNewline; while ((uint32_t)lastRealChar > posInString && nsCRT::IsAsciiSpace(tString[lastRealChar-1])) { --lastRealChar; } aOutString += Substring(tString, posInString, lastRealChar - posInString); outStringCol += lastRealChar - posInString; posInString = nextNewline + 1; continue; } int32_t eol = posInString + aWrapCol - citeLevel - outStringCol; // eol is the prospective end of line. // We'll first look backwards from there for a place to break. // If it's already less than our current position, // then our line is already too long, so break now. if (eol <= (int32_t)posInString) { BreakLine(aOutString, outStringCol, citeLevel); continue; // continue inner loop, with outStringCol now at bol } int32_t breakPt = 0; // XXX Why this uses NS_ERROR_"BASE"? rv = NS_ERROR_BASE; if (lineBreaker) { breakPt = lineBreaker->Prev(tString.get() + posInString, length - posInString, eol + 1 - posInString); if (breakPt == NS_LINEBREAKER_NEED_MORE_TEXT) { // if we couldn't find a breakpoint looking backwards, // and we're not starting a new line, then end this line // and loop around again: if (outStringCol > citeLevel + 1) { BreakLine(aOutString, outStringCol, citeLevel); continue; // continue inner loop, with outStringCol now at bol } // Else try looking forwards: breakPt = lineBreaker->Next(tString.get() + posInString, length - posInString, eol - posInString); rv = breakPt == NS_LINEBREAKER_NEED_MORE_TEXT ? NS_ERROR_BASE : NS_OK; } else { rv = NS_OK; } } // If rv is okay, then breakPt is the place to break. // If we get out here and rv is set, something went wrong with line // breaker. Just break the line, hard. if (NS_FAILED(rv)) { breakPt = eol; } // Special case: maybe we should have wrapped last time. // If the first breakpoint here makes the current line too long, // then if we already have text on the current line, // break and loop around again. // If we're at the beginning of the current line, though, // don't force a break since the long word might be a url // and breaking it would make it unclickable on the other end. const int SLOP = 6; if (outStringCol + breakPt > aWrapCol + SLOP && outStringCol > citeLevel+1) { BreakLine(aOutString, outStringCol, citeLevel); continue; } nsAutoString sub (Substring(tString, posInString, breakPt)); // skip newlines or whitespace at the end of the string int32_t subend = sub.Length(); while (subend > 0 && IsSpace(sub[subend-1])) { --subend; } sub.Left(sub, subend); aOutString += sub; outStringCol += sub.Length(); // Advance past the whitespace which caused the wrap: posInString += breakPt; while (posInString < length && IsSpace(tString[posInString])) { ++posInString; } // Add a newline and the quote level to the out string if (posInString < length) { // not for the last line, though BreakLine(aOutString, outStringCol, citeLevel); } } // end inner loop within one line of aInString } // end outer loop over lines of aInString return NS_OK; }
unsigned int FixedLine::SetLine(unsigned int startpos, unsigned int endpos, bool cache) { m_docLen = m_doc.GetLength(); #ifdef __WXDEBUG__ wxASSERT(!m_inSetLine); // re-entrancy check m_inSetLine = true; wxASSERT(startpos >= 0 && startpos < m_docLen); wxASSERT(endpos > startpos && endpos <= m_docLen); if (startpos > 0) { wxChar c; cxLOCKDOC_READ(m_doc) c = doc.GetChar(startpos - 1); cxENDLOCK wxASSERT(c == wxT('\n')); } if (endpos < m_docLen) { wxChar c; cxLOCKDOC_READ(m_doc) c = doc.GetChar(endpos - 1); cxENDLOCK wxASSERT(c == wxT('\n')); } #endif if (!cache || startpos != textstart || endpos != textend) { textstart = startpos; textend = endpos; m_lineLen = endpos - startpos; // Check if we need to resize line buffer if (m_lineBufferLen < m_lineLen) { m_lineBufferLen = m_lineLen; m_lineBuffer = wxCharBuffer(m_lineBufferLen); // wxCharBuffer allocs room for & adds nullbyte at len } // Cache the current line in lineBuffer (as UTF-8) cxLOCKDOC_READ(m_doc) doc.GetTextPart(textstart, textend, (unsigned char*)m_lineBuffer.data()); cxENDLOCK // Style the lines m_sr.Init(textstart, textend); for (vector<Styler*>::iterator si = m_stylers.begin(); si != m_stylers.end(); ++si) { (*si)->Style(m_sr); } m_extents.clear(); m_extents.reserve(m_lineLen); unsigned int xpos = 0; unsigned int lastpos = 0; unsigned int style_start = 0; int fontStyle = m_sr.GetFontStyle(0); char* dbi = m_lineBuffer.data(); // Build list of text extends (totalling) compensating for tabs and styles // There is one extent per byte in the text. In utf8 chars composed out of multiple // bytes, they will all have same value. for (unsigned int style_id = 0; style_id < m_sr.GetStyleCount(); ++style_id) { const unsigned int style_end = m_sr.GetStyleEnd(style_id) - textstart; // Ignore zero length styles if (style_start == style_end) continue; // Check for style change if (m_sr.GetFontStyle(style_id) != fontStyle) { if (style_start > lastpos) { m_sr.ApplyFontStyle(fontStyle); // Get extends for current segment m_extsBuf.clear(); const unsigned int seg_len = style_start-lastpos; const wxString text(dbi+lastpos, wxConvUTF8, seg_len); dc.GetPartialTextExtents(text, m_extsBuf); wxASSERT(!text.empty() && m_extsBuf.size() == text.size()); // Add to main list adjusted for offset unsigned int extpos = 0; unsigned int offset = xpos; for (unsigned int i = lastpos; i < style_start; ++i) { if ((dbi[i] & 0xC0) == 0x80) m_extents.push_back(xpos); // Only count first byte of UTF-8 multibyte chars else if (dbi[i] == '\t') { // Add tab extend xpos = ((xpos / tabwidth)+1) * tabwidth; // GetTabPoint(xpos); offset += xpos - (m_extsBuf[extpos] + offset); m_extents.push_back(xpos); ++extpos; } else { xpos = m_extsBuf[extpos] + offset; m_extents.push_back(xpos); ++extpos; } } // Small hack to make lines that end with italics not cut off the edge of the last character if (fontStyle &= wxFONTFLAG_ITALIC) { m_extents.back() += 2; xpos = m_extents.back(); } } lastpos = style_start; fontStyle = m_sr.GetFontStyle(style_id); } style_start = style_end; } // Add extends for last segment if (lastpos < m_lineLen) { m_sr.ApplyFontStyle(fontStyle); // Get extends for current segment m_extsBuf.clear(); const unsigned int seg_len = m_lineLen-lastpos; const wxString text(dbi+lastpos, wxConvUTF8, seg_len); dc.GetPartialTextExtents(text, m_extsBuf); wxASSERT(!text.empty() && m_extsBuf.size() == text.size()); // Add to main list adjusted for offset unsigned int extpos = 0; unsigned int offset = xpos; for (unsigned int i = lastpos; i < m_lineLen; ++i) { if ((dbi[i] & 0xC0) == 0x80) m_extents.push_back(xpos); // Only count first byte of UTF-8 multibyte chars else if (dbi[i] == '\t') { // Add tab extend xpos = ((xpos / tabwidth)+1) * tabwidth; // GetTabPoint(xpos); offset += xpos - (m_extsBuf[extpos] + offset); m_extents.push_back(xpos); ++extpos; } else { xpos = m_extsBuf[extpos] + offset; m_extents.push_back(xpos); ++extpos; } } } wxASSERT(m_extents.size() == m_lineLen); BreakLine(); } else if (width != old_width) { wxASSERT(m_extents.size() == m_lineLen); BreakLine(); } #ifdef __WXDEBUG__ m_inSetLine = false; // re-entrancy check #endif return (m_wrapMode == cxWRAP_NONE) ? m_lineWidth : height; }
int InsertFromFrame( CFrameNode *pFrameNode, SelectNode &sn, int fUpCalc, SelectInfo *psi ) { if( pFrameNode == NULL ) return -1; if( pFrameNode->GetChildCount() == 1 ) { Q_ASSERT( pFrameNode->GetFirstChild()->GetType() == NODE_LINE ); return ::InsertFromLine( (CLineNode*) pFrameNode->GetChild( 0 ), sn, fUpCalc, psi ); } else { Q_ASSERT( pFrameNode->GetChildCount() > 0 ); BreakLine( sn, 0 ); CNode *pPrev = sn.GetNode()->GetPrev(); CNode *pNext = sn.GetNode(); Q_ASSERT( pPrev ); Q_ASSERT( pNext ); CParentNode *pParentNode = sn.GetNode()->GetParent(); int fRecalculateFull = (pFrameNode->GetLevel() != pParentNode->GetLevel()); QVector<CNode*> children; pFrameNode->RecalculateSizeFull(); pFrameNode->RemoveOrCopyChildren( children ); if( psi ) { psi->GetBegin().SetNode( children[ 0 ] ); psi->GetBegin().SetPosition( 0 ); psi->GetEnd() = sn; } pParentNode->InsertChildren( children, pParentNode->GetChildIndex( sn.GetNode() ) ); if( pNext->GetPrev() == pPrev ) { Q_ASSERT( 0 ); } else { if( GlueLine( sn, pNext->GetPrev(), 0, NULL ) == 0 ) if( psi ) psi->GetEnd() = sn; if( GlueLine( sn, pPrev, 0, NULL ) == 0 ) if( psi ) psi->GetBegin() = sn; } if( fRecalculateFull ) pParentNode->RecalculateSizeFull(); else pParentNode->RecalculateSize( 0 ); if( pParentNode->GetParent() ) pParentNode->GetParent()->RecalculateSize( fUpCalc ); return 0; } }
CPlaneText* InsertPlaneText( SelectNode &sn, QString &strText, long style, RealFde kegl, CNodeInfo& ni, CNodeExInfo& ex_ni ) { if( ni.isUnicode() ) { if( sn.GetNode()->GetType() == NODE_PLANETEXT ) BreakPlaneText( sn, 0 ); Q_ASSERT( sn.GetNode()->GetType() == NODE_LINE ); CParentNode *pParentNode = sn.GetNode()->GetParent(); CNode *pPrev, *pNext; GetPrevNextInLine( sn, pPrev, pNext ); long nLen; QString str; CPlaneText *pPlaneText = NULL; while( (nLen = strText.length()) ) { long nPos = strText.indexOf("\r\n"); if( nPos == -1 ) { str = strText.mid(0, nLen); strText.clear(); } else { str = strText.mid(0, nPos + 2); strText.remove(0, nPos); } pPlaneText = InsertPlaneText_Internal( sn, str, style, kegl, ni, ex_ni ); if( nPos != -1 ) BreakLine( sn, 0 ); } pPlaneText->GetParent()->RecalculateSize( 0 ); if( pPrev ) GlueText( sn, pPrev, 0 ); if( pNext ) GlueText( sn, pNext->GetPrev(), 0 ); pParentNode->RecalculateSize( 1 ); return pPlaneText; } else { if( sn.GetNode()->GetType() == NODE_PLANETEXT ) BreakPlaneText( sn, 0 ); Q_ASSERT( sn.GetNode()->GetType() == NODE_LINE ); CParentNode *pParentNode = sn.GetNode()->GetParent(); CNode *pPrev, *pNext; GetPrevNextInLine( sn, pPrev, pNext ); // long i, cb; long nLen; QString str; QVector<CNode*> texts, lines; while( (nLen = strText.length()) ) { long nPos = strText.indexOf( "\r\n" ); if( nPos == -1 ) { str = strText.mid(0, nLen); strText.clear(); } else { str = strText.mid(0, nPos); strText.remove( 0, nPos + 2 ); } lines.push_back( sn.GetNode()->GetLineNode() ); char ch = 0; LFInsertStyle style2analyse; long nNewStyle = -1; for( cb = 0; ; ) { ch = style2analyse.Analisys( str.midRef(cb) ); if( ch == 0 ) break; if( style == -1 ) nNewStyle = ::getCurrentFormulatorStyle().getStyleByCharOnly( ch ); else nNewStyle = style; QString sV( style2analyse.getText() ); texts.push_back( InsertPlaneText_Internal( sn, sV, nNewStyle, kegl, ni, ex_ni, 0 ) ); cb += style2analyse.GetRead(); style2analyse.reset(); } if( nPos != -1 ) BreakLine( sn, 0 ); } for( i = 0; i < (long) texts.size(); i++ ) { Q_ASSERT( texts[ i ] != NULL ); texts[ i ]->RecalculateSize( 0 ); } for( i = 0; i < (long) lines.size(); i++ ) { Q_ASSERT( lines[ i ] != NULL ); lines[ i ]->RecalculateSize( 0 ); } if( pPrev ) GlueText( sn, pPrev, 0 ); if( pNext ) GlueText( sn, pNext->GetPrev(), 0 ); pParentNode->RecalculateSize( 1 ); return (CPlaneText*) (texts.size() ? texts[ texts.size() - 1 ] : NULL); } }
NS_IMETHODIMP nsInternetCiter::Rewrap(const nsAString& aInString, PRUint32 aWrapCol, PRUint32 aFirstLineOffset, PRBool aRespectNewlines, nsAString& aOutString) { // There shouldn't be returns in this string, only dom newlines. // Check to make sure: #ifdef DEBUG PRInt32 cr = aInString.FindChar(PRUnichar('\r')); NS_ASSERTION((cr < 0), "Rewrap: CR in string gotten from DOM!\n"); #endif /* DEBUG */ aOutString.Truncate(); nsCOMPtr<nsILineBreaker> lineBreaker; nsILineBreakerFactory *lf; nsresult rv; rv = CallGetService(NS_LWBRK_CONTRACTID, &lf); if (NS_SUCCEEDED(rv)) { nsAutoString lbarg; lf->GetBreaker(lbarg, getter_AddRefs(lineBreaker)); NS_RELEASE(lf); } // Loop over lines in the input string, rewrapping each one. PRUint32 length; PRUint32 posInString = 0; PRUint32 outStringCol = 0; PRUint32 citeLevel = 0; const nsPromiseFlatString &tString = PromiseFlatString(aInString); length = tString.Length(); #ifdef DEBUG_wrapping int loopcount = 0; #endif while (posInString < length) { #ifdef DEBUG_wrapping printf("Outer loop: '%s'\n", NS_LossyConvertUCS2toASCII(Substring(tString, posInString, length-posInString)).get()); printf("out string is now: '%s'\n", NS_LossyConvertUCS2toASCII(aOutString).get()); #endif // Get the new cite level here since we're at the beginning of a line PRUint32 newCiteLevel = 0; while (posInString < length && tString[posInString] == gt) { ++newCiteLevel; ++posInString; while (posInString < length && tString[posInString] == space) ++posInString; } if (posInString >= length) break; // Special case: if this is a blank line, maintain a blank line // (retain the original paragraph breaks) if (tString[posInString] == nl && !aOutString.IsEmpty()) { if (aOutString.Last() != nl) aOutString.Append(nl); AddCite(aOutString, newCiteLevel); aOutString.Append(nl); ++posInString; outStringCol = 0; continue; } // If the cite level has changed, then start a new line with the // new cite level (but if we're at the beginning of the string, // don't bother). if (newCiteLevel != citeLevel && posInString > newCiteLevel+1 && outStringCol != 0) { BreakLine(aOutString, outStringCol, 0); } citeLevel = newCiteLevel; // Prepend the quote level to the out string if appropriate if (outStringCol == 0) { AddCite(aOutString, citeLevel); outStringCol = citeLevel + (citeLevel ? 1 : 0); } // If it's not a cite, and we're not at the beginning of a line in // the output string, add a space to separate new text from the // previous text. else if (outStringCol > citeLevel) { aOutString.Append(space); ++outStringCol; } // find the next newline -- don't want to go farther than that PRInt32 nextNewline = tString.FindChar(nl, posInString); if (nextNewline < 0) nextNewline = length; // For now, don't wrap unquoted lines at all. // This is because the plaintext edit window has already wrapped them // by the time we get them for rewrap, yet when we call the line // breaker, it will refuse to break backwards, and we'll end up // with a line that's too long and gets displayed as a lone word // on a line by itself. Need special logic to detect this case // and break it ourselves without resorting to the line breaker. if (citeLevel == 0) { aOutString.Append(Substring(tString, posInString, nextNewline-posInString)); outStringCol += nextNewline - posInString; if (nextNewline != (PRInt32)length) { aOutString.Append(nl); outStringCol = 0; } posInString = nextNewline+1; continue; } // Otherwise we have to use the line breaker and loop // over this line of the input string to get all of it: while ((PRInt32)posInString < nextNewline) { #ifdef DEBUG_wrapping if (++loopcount > 1000) NS_ASSERTION(PR_FALSE, "possible infinite loop in nsInternetCiter\n"); printf("Inner loop: '%s'\n", NS_LossyConvertUCS2toASCII(Substring(tString, posInString, nextNewline-posInString)).get()); #endif // Skip over initial spaces: while ((PRInt32)posInString < nextNewline && nsCRT::IsAsciiSpace(tString[posInString])) ++posInString; // If this is a short line, just append it and continue: if (outStringCol + nextNewline - posInString <= aWrapCol-citeLevel-1) { // If this short line is the final one in the in string, // then we need to include the final newline, if any: if (nextNewline+1 == (PRInt32)length && tString[nextNewline-1] == nl) ++nextNewline; // Trim trailing spaces: PRInt32 lastRealChar = nextNewline; while ((PRUint32)lastRealChar > posInString && nsCRT::IsAsciiSpace(tString[lastRealChar-1])) --lastRealChar; aOutString += Substring(tString, posInString, lastRealChar - posInString); outStringCol += lastRealChar - posInString; posInString = nextNewline + 1; continue; } PRInt32 eol = posInString + aWrapCol - citeLevel - outStringCol; // eol is the prospective end of line. // We'll first look backwards from there for a place to break. // If it's already less than our current position, // then our line is already too long, so break now. if (eol <= (PRInt32)posInString) { BreakLine(aOutString, outStringCol, citeLevel); continue; // continue inner loop, with outStringCol now at bol } PRUint32 breakPt; rv = NS_ERROR_BASE; if (lineBreaker) { PRBool needMore; rv = lineBreaker->Prev(tString.get() + posInString, length - posInString, eol + 1 - posInString, &breakPt, &needMore); if (NS_FAILED(rv) || needMore) { // if we couldn't find a breakpoint looking backwards, // and we're not starting a new line, then end this line // and loop around again: if (outStringCol > citeLevel + 1) { BreakLine(aOutString, outStringCol, citeLevel); continue; // continue inner loop, with outStringCol now at bol } // Else try looking forwards: rv = lineBreaker->Next(tString.get() + posInString, length - posInString, eol - posInString, &breakPt, &needMore); if (needMore) rv = NS_ERROR_BASE; } } // If rv is okay, then breakPt is the place to break. // If we get out here and rv is set, something went wrong with line // breaker. Just break the line, hard. if (NS_FAILED(rv)) { #ifdef DEBUG_akkana printf("nsInternetCiter: LineBreaker not working -- breaking hard\n"); #endif breakPt = eol; } // Special case: maybe we should have wrapped last time. // If the first breakpoint here makes the current line too long, // then if we already have text on the current line, // break and loop around again. // If we're at the beginning of the current line, though, // don't force a break since the long word might be a url // and breaking it would make it unclickable on the other end. const int SLOP = 6; if (outStringCol + breakPt > aWrapCol + SLOP && outStringCol > citeLevel+1) { BreakLine(aOutString, outStringCol, citeLevel); continue; } nsAutoString sub (Substring(tString, posInString, breakPt)); // skip newlines or whitespace at the end of the string PRInt32 subend = sub.Length(); while (subend > 0 && IsSpace(sub[subend-1])) --subend; sub.Left(sub, subend); aOutString += sub; outStringCol += sub.Length(); // Advance past the whitespace which caused the wrap: posInString += breakPt; while (posInString < length && IsSpace(tString[posInString])) ++posInString; // Add a newline and the quote level to the out string if (posInString < length) // not for the last line, though BreakLine(aOutString, outStringCol, citeLevel); } // end inner loop within one line of aInString #ifdef DEBUG_wrapping printf("---------\nEnd inner loop: out string is now '%s'\n-----------\n", NS_LossyConvertUCS2toASCII(aOutString).get()); #endif } // end outer loop over lines of aInString #ifdef DEBUG_wrapping printf("Final out string is now: '%s'\n", NS_LossyConvertUCS2toASCII(aOutString).get()); #endif return NS_OK; }