PRUint32 nsConverterInputStream::Fill(nsresult * aErrorCode) { if (nsnull == mInput) { // We already closed the stream! *aErrorCode = NS_BASE_STREAM_CLOSED; return 0; } if (NS_FAILED(mLastErrorCode)) { // We failed to completely convert last time, and error-recovery // is disabled. We will fare no better this time, so... *aErrorCode = mLastErrorCode; return 0; } // We assume a many to one conversion and are using equal sizes for // the two buffers. However if an error happens at the very start // of a byte buffer we may end up in a situation where n bytes lead // to n+1 unicode chars. Thus we need to keep track of the leftover // bytes as we convert. PRInt32 nb = mByteData->Fill(aErrorCode, mInput, mLeftOverBytes); #if defined(DEBUG_bzbarsky) && 0 for (unsigned int foo = 0; foo < mByteData->GetLength(); ++foo) { fprintf(stderr, "%c", mByteData->GetBuffer()[foo]); } fprintf(stderr, "\n"); #endif if (nb <= 0 && mLeftOverBytes == 0) { // No more data *aErrorCode = NS_OK; return 0; } NS_ASSERTION(PRUint32(nb) + mLeftOverBytes == mByteData->GetLength(), "mByteData is lying to us somewhere"); // Now convert as much of the byte buffer to unicode as possible mUnicharDataOffset = 0; mUnicharDataLength = 0; PRUint32 srcConsumed = 0; do { PRInt32 srcLen = mByteData->GetLength() - srcConsumed; PRInt32 dstLen = mUnicharData->GetBufferSize() - mUnicharDataLength; *aErrorCode = mConverter->Convert(mByteData->GetBuffer()+srcConsumed, &srcLen, mUnicharData->GetBuffer()+mUnicharDataLength, &dstLen); mUnicharDataLength += dstLen; // XXX if srcLen is negative, we want to drop the _first_ byte in // the erroneous byte sequence and try again. This is not quite // possible right now -- see bug 160784 srcConsumed += srcLen; if (NS_FAILED(*aErrorCode) && mReplacementChar) { NS_ASSERTION(0 < mUnicharData->GetBufferSize() - mUnicharDataLength, "Decoder returned an error but filled the output buffer! " "Should not happen."); mUnicharData->GetBuffer()[mUnicharDataLength++] = mReplacementChar; ++srcConsumed; // XXX this is needed to make sure we don't underrun our buffer; // bug 160784 again srcConsumed = NS_MAX<PRUint32>(srcConsumed, 0); mConverter->Reset(); } NS_ASSERTION(srcConsumed <= mByteData->GetLength(), "Whoa. The converter should have returned NS_OK_UDEC_MOREINPUT before this point!"); } while (mReplacementChar && NS_FAILED(*aErrorCode) && mUnicharData->GetBufferSize() > mUnicharDataLength); mLeftOverBytes = mByteData->GetLength() - srcConsumed; return mUnicharDataLength; }
// |decode_mime_part2_str| taken from comi18n.c // Decode RFC2047-encoded words in the input and convert the result to UTF-8. // If aOverrideCharset is true, charset in RFC2047-encoded words is // ignored and aDefaultCharset is assumed, instead. aDefaultCharset // is also used to convert raw octets (without RFC 2047 encoding) to UTF-8. //static nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, PRBool aOverrideCharset, nsACString &aResult) { const char *p, *q, *r; char *decodedText; const char *begin; // tracking pointer for where we are in the input buffer PRInt32 isLastEncodedWord = 0; const char *charsetStart, *charsetEnd; char charset[80]; // initialize charset name to an empty string charset[0] = '\0'; begin = aHeader; // To avoid buffer realloc, if possible, set capacity in advance. No // matter what, more than 3x expansion can never happen for all charsets // supported by Mozilla. SCSU/BCSU with the sliding window set to a // non-BMP block may be exceptions, but Mozilla does not support them. // Neither any known mail/news program use them. Even if there's, we're // safe because we don't use a raw *char any more. aResult.SetCapacity(3 * strlen(aHeader)); while ((p = PL_strstr(begin, "=?")) != 0) { if (isLastEncodedWord) { // See if it's all whitespace. for (q = begin; q < p; ++q) { if (!PL_strchr(" \t\r\n", *q)) break; } } if (!isLastEncodedWord || q < p) { // copy the part before the encoded-word CopyRawHeader(begin, p - begin, aDefaultCharset, aResult); begin = p; } p += 2; // Get charset info charsetStart = p; charsetEnd = 0; for (q = p; *q != '?'; q++) { if (*q <= ' ' || PL_strchr(especials, *q)) { goto badsyntax; } // RFC 2231 section 5 if (!charsetEnd && *q == '*') { charsetEnd = q; } } if (!charsetEnd) { charsetEnd = q; } // Check for too-long charset name if (PRUint32(charsetEnd - charsetStart) >= sizeof(charset)) goto badsyntax; memcpy(charset, charsetStart, charsetEnd - charsetStart); charset[charsetEnd - charsetStart] = 0; q++; if (*q != 'Q' && *q != 'q' && *q != 'B' && *q != 'b') goto badsyntax; if (q[1] != '?') goto badsyntax; r = q; for (r = q + 2; *r != '?'; r++) { if (*r < ' ') goto badsyntax; } if (r[1] != '=') goto badsyntax; else if (r == q + 2) { // it's empty, skip begin = r + 2; isLastEncodedWord = 1; continue; } if(*q == 'Q' || *q == 'q') decodedText = DecodeQ(q + 2, r - (q + 2)); else { // bug 227290. ignore an extraneous '=' at the end. // (# of characters in B-encoded part has to be a multiple of 4) PRInt32 n = r - (q + 2); n -= (n % 4 == 1 && !PL_strncmp(r - 3, "===", 3)) ? 1 : 0; decodedText = PL_Base64Decode(q + 2, n, nsnull); } if (decodedText == nsnull) goto badsyntax; // Override charset if requested. Never override labeled UTF-8. // Use default charset instead of UNKNOWN-8BIT if ((aOverrideCharset && 0 != nsCRT::strcasecmp(charset, "UTF-8")) || (aDefaultCharset && 0 == nsCRT::strcasecmp(charset, "UNKNOWN-8BIT"))) { PL_strncpy(charset, aDefaultCharset, sizeof(charset) - 1); charset[sizeof(charset) - 1] = '\0'; } { nsCOMPtr<nsIUTF8ConverterService> cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID)); nsCAutoString utf8Text; // skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset. if (cvtUTF8 && NS_SUCCEEDED( cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText), charset, IS_7BIT_NON_ASCII_CHARSET(charset), utf8Text))) { aResult.Append(utf8Text); } else { aResult.Append(REPLACEMENT_CHAR); } } PR_Free(decodedText); begin = r + 2; isLastEncodedWord = 1; continue; badsyntax: // copy the part before the encoded-word aResult.Append(begin, p - begin); begin = p; isLastEncodedWord = 0; } // put the tail back CopyRawHeader(begin, strlen(begin), aDefaultCharset, aResult); nsCAutoString tempStr(aResult); tempStr.ReplaceChar('\t', ' '); aResult = tempStr; return NS_OK; }
PRUint32 nsInputStreamPump::OnStateTransfer() { SAMPLE_LABEL("Input", "nsInputStreamPump::OnStateTransfer"); LOG((" OnStateTransfer [this=%x]\n", this)); // if canceled, go directly to STATE_STOP... if (NS_FAILED(mStatus)) return STATE_STOP; nsresult rv; PRUint32 avail; rv = mAsyncStream->Available(&avail); LOG((" Available returned [stream=%x rv=%x avail=%u]\n", mAsyncStream.get(), rv, avail)); if (rv == NS_BASE_STREAM_CLOSED) { rv = NS_OK; avail = 0; } else if (NS_SUCCEEDED(rv) && avail) { // figure out how much data to report (XXX detect overflow??) if (PRUint64(avail) + mStreamOffset > mStreamLength) avail = PRUint32(mStreamLength - mStreamOffset); if (avail) { // we used to limit avail to 16K - we were afraid some ODA handlers // might assume they wouldn't get more than 16K at once // we're removing that limit since it speeds up local file access. // Now there's an implicit 64K limit of 4 16K segments // NOTE: ok, so the story is as follows. OnDataAvailable impls // are by contract supposed to consume exactly |avail| bytes. // however, many do not... mailnews... stream converters... // cough, cough. the input stream pump is fairly tolerant // in this regard; however, if an ODA does not consume any // data from the stream, then we could potentially end up in // an infinite loop. we do our best here to try to catch // such an error. (see bug 189672) // in most cases this QI will succeed (mAsyncStream is almost always // a nsPipeInputStream, which implements nsISeekableStream::Tell). PRInt64 offsetBefore; nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mAsyncStream); if (seekable && NS_FAILED(seekable->Tell(&offsetBefore))) { NS_NOTREACHED("Tell failed on readable stream"); offsetBefore = 0; } // report the current stream offset to our listener... if we've // streamed more than PR_UINT32_MAX, then avoid overflowing the // stream offset. it's the best we can do without a 64-bit stream // listener API. PRUint32 odaOffset = mStreamOffset > PR_UINT32_MAX ? PR_UINT32_MAX : PRUint32(mStreamOffset); LOG((" calling OnDataAvailable [offset=%lld(%u) count=%u]\n", mStreamOffset, odaOffset, avail)); rv = mListener->OnDataAvailable(this, mListenerContext, mAsyncStream, odaOffset, avail); // don't enter this code if ODA failed or called Cancel if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) { // test to see if this ODA failed to consume data if (seekable) { // NOTE: if Tell fails, which can happen if the stream is // now closed, then we assume that everything was read. PRInt64 offsetAfter; if (NS_FAILED(seekable->Tell(&offsetAfter))) offsetAfter = offsetBefore + avail; if (offsetAfter > offsetBefore) mStreamOffset += (offsetAfter - offsetBefore); else if (mSuspendCount == 0) { // // possible infinite loop if we continue pumping data! // // NOTE: although not allowed by nsIStreamListener, we // will allow the ODA impl to Suspend the pump. IMAP // does this :-( // NS_ERROR("OnDataAvailable implementation consumed no data"); mStatus = NS_ERROR_UNEXPECTED; } } else mStreamOffset += avail; // assume ODA behaved well } } } // an error returned from Available or OnDataAvailable should cause us to // abort; however, we must not stomp on mStatus if already canceled. if (NS_SUCCEEDED(mStatus)) { if (NS_FAILED(rv)) mStatus = rv; else if (avail) { // if stream is now closed, advance to STATE_STOP right away. // Available may return 0 bytes available at the moment; that // would not mean that we are done. // XXX async streams should have a GetStatus method! rv = mAsyncStream->Available(&avail); if (NS_SUCCEEDED(rv)) return STATE_TRANSFER; } } return STATE_STOP; }
bool mozTXTToHTMLConv::FindURLEnd(const PRUnichar * aInString, PRInt32 aInStringLength, const PRUint32 pos, const modetype check, const PRUint32 start, PRUint32& end) { switch(check) { // no breaks, because end of blocks is never reached case RFC1738: case RFC2396E: { nsString temp(aInString, aInStringLength); PRInt32 i = temp.FindCharInSet(NS_LITERAL_STRING("<>\"").get(), pos + 1); if (i != kNotFound && temp[PRUint32(i--)] == (check == RFC1738 || temp[start - 1] == '<' ? '>' : '"')) { end = PRUint32(i); return end > pos; } else return false; } case freetext: case abbreviated: { PRUint32 i = pos + 1; bool isEmail = aInString[pos] == (PRUnichar)'@'; bool haveOpeningBracket = false; for (; PRInt32(i) < aInStringLength; i++) { // These chars mark the end of the URL if (aInString[i] == '>' || aInString[i] == '<' || aInString[i] == '"' || aInString[i] == '`' || aInString[i] == '}' || aInString[i] == ']' || aInString[i] == '{' || aInString[i] == '[' || aInString[i] == '|' || (aInString[i] == ')' && !haveOpeningBracket) || IsSpace(aInString[i]) ) break; // Disallow non-ascii-characters for email. // Currently correct, but revisit later after standards changed. if (isEmail && ( aInString[i] == '(' || aInString[i] == '\'' || !nsCRT::IsAscii(aInString[i]) )) break; if (aInString[i] == '(') haveOpeningBracket = true; } // These chars are allowed in the middle of the URL, but not at end. // Technically they are, but are used in normal text after the URL. while (--i > pos && ( aInString[i] == '.' || aInString[i] == ',' || aInString[i] == ';' || aInString[i] == '!' || aInString[i] == '?' || aInString[i] == '-' || aInString[i] == ':' || aInString[i] == '\'' )) ; if (i > pos) { end = i; return true; } else return false; } default: return false; } //switch }
nsresult nsHtml5TreeOperation::Perform(nsHtml5TreeBuilder* aBuilder) { nsresult rv = NS_OK; switch(mOpCode) { case eTreeOpAppend: { aBuilder->PostPendingAppendNotification(mParent, mNode); rv = mParent->AppendChildTo(mNode, PR_FALSE); return rv; } case eTreeOpDetach: { aBuilder->FlushPendingAppendNotifications(); nsIContent* parent = mNode->GetParent(); if (parent) { PRUint32 pos = parent->IndexOf(mNode); NS_ASSERTION((pos >= 0), "Element not found as child of its parent"); rv = parent->RemoveChildAt(pos, PR_TRUE, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); } return rv; } case eTreeOpAppendChildrenToNewParent: { aBuilder->FlushPendingAppendNotifications(); PRUint32 childCount = mParent->GetChildCount(); PRBool didAppend = PR_FALSE; while (mNode->GetChildCount()) { nsCOMPtr<nsIContent> child = mNode->GetChildAt(0); rv = mNode->RemoveChildAt(0, PR_TRUE, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); rv = mParent->AppendChildTo(child, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); didAppend = PR_TRUE; } if (didAppend) { nsNodeUtils::ContentAppended(mParent, childCount); } return rv; } case eTreeOpFosterParent: { nsIContent* parent = mTable->GetParent(); if (parent && parent->IsNodeOfType(nsINode::eELEMENT)) { aBuilder->FlushPendingAppendNotifications(); PRUint32 pos = parent->IndexOf(mTable); rv = parent->InsertChildAt(mNode, pos, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); nsNodeUtils::ContentInserted(parent, mNode, pos); } else { aBuilder->PostPendingAppendNotification(mParent, mNode); rv = mParent->AppendChildTo(mNode, PR_FALSE); } return rv; } case eTreeOpAppendToDocument: { aBuilder->FlushPendingAppendNotifications(); nsIDocument* doc = aBuilder->GetDocument(); PRUint32 childCount = doc->GetChildCount(); rv = doc->AppendChildTo(mNode, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); nsNodeUtils::ContentInserted(doc, mNode, childCount); return rv; } case eTreeOpAddAttributes: { // mNode holds the new attributes and mParent is the target nsIDocument* document = mParent->GetCurrentDoc(); PRUint32 len = mNode->GetAttrCount(); for (PRUint32 i = 0; i < len; ++i) { const nsAttrName* attrName = mNode->GetAttrNameAt(i); nsIAtom* localName = attrName->LocalName(); PRInt32 nsuri = attrName->NamespaceID(); if (!mParent->HasAttr(nsuri, localName)) { nsAutoString value; mNode->GetAttr(nsuri, localName, value); // the manual notification code is based on nsGenericElement PRUint32 stateMask = PRUint32(mParent->IntrinsicState()); nsNodeUtils::AttributeWillChange(mParent, nsuri, localName, static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION)); mParent->SetAttr(nsuri, localName, attrName->GetPrefix(), value, PR_FALSE); if (document || mParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) { nsIDocument* ownerDoc = mParent->GetOwnerDoc(); if (ownerDoc) { nsRefPtr<nsXBLBinding> binding = ownerDoc->BindingManager()->GetBinding(mParent); if (binding) { binding->AttributeChanged(localName, nsuri, PR_FALSE, PR_FALSE); } } } stateMask = stateMask ^ PRUint32(mParent->IntrinsicState()); if (stateMask && document) { MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE); document->ContentStatesChanged(mParent, nsnull, stateMask); } nsNodeUtils::AttributeChanged(mParent, nsuri, localName, static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION), stateMask); } } return rv; } case eTreeOpDoneAddingChildren: { mNode->DoneAddingChildren(PR_FALSE); return rv; } case eTreeOpDoneCreatingElement: { mNode->DoneCreatingElement(); return rv; } case eTreeOpUpdateStyleSheet: { aBuilder->UpdateStyleSheet(mNode); return rv; } case eTreeOpProcessBase: { rv = aBuilder->ProcessBase(mNode); return rv; } case eTreeOpProcessMeta: { rv = aBuilder->ProcessMeta(mNode); return rv; } case eTreeOpProcessOfflineManifest: { rv = aBuilder->ProcessOfflineManifest(mNode); return rv; } case eTreeOpStartLayout: { aBuilder->StartLayout(); // this causes a flush anyway return rv; } default: { NS_NOTREACHED("Bogus tree op"); } } return rv; // keep compiler happy }
static nsresult ConnRead(ipcConnectionState *s) { char buf[1024]; nsresult rv = NS_OK; PRInt32 n; do { n = PR_Read(s->fds[SOCK].fd, buf, sizeof(buf)); if (n < 0) { PRErrorCode err = PR_GetError(); if (err == PR_WOULD_BLOCK_ERROR) { // socket is empty... we need to go back to polling. break; } LOG(("PR_Read returned failure [err=%d]\n", err)); rv = NS_ERROR_UNEXPECTED; } else if (n == 0) { LOG(("PR_Read returned EOF\n")); rv = NS_ERROR_UNEXPECTED; } else { const char *pdata = buf; while (n) { PRUint32 bytesRead; PRBool complete; if (!s->in_msg) { s->in_msg = new ipcMessage; if (!s->in_msg) { rv = NS_ERROR_OUT_OF_MEMORY; break; } } if (s->in_msg->ReadFrom(pdata, n, &bytesRead, &complete) != PR_SUCCESS) { LOG(("error reading IPC message\n")); rv = NS_ERROR_UNEXPECTED; break; } PR_ASSERT(PRUint32(n) >= bytesRead); n -= bytesRead; pdata += bytesRead; if (complete) { // protect against weird re-entrancy cases... ipcMessage *m = s->in_msg; s->in_msg = NULL; IPC_OnMessageAvailable(m); } } } } while (NS_SUCCEEDED(rv)); return rv; }
void mozTXTToHTMLConv::ScanHTML(nsString& aInString, PRUint32 whattodo, nsString &aOutString) { // some common variables we were recalculating // every time inside the for loop... PRInt32 lengthOfInString = aInString.Length(); const PRUnichar * uniBuffer = aInString.get(); #ifdef DEBUG_BenB_Perf PRTime parsing_start = PR_IntervalNow(); #endif // Look for simple entities not included in a tags and scan them. /* Skip all tags ("<[...]>") and content in an a tag ("<a[...]</a>") or in a tag ("<!--[...]-->"). Unescape the rest (text between tags) and pass it to ScanTXT. */ for (PRInt32 i = 0; i < lengthOfInString;) { if (aInString[i] == '<') // html tag { PRUint32 start = PRUint32(i); if (nsCRT::ToLower((char)aInString[PRUint32(i) + 1]) == 'a') // if a tag, skip until </a> { i = aInString.Find("</a>", true, i); if (i == kNotFound) i = lengthOfInString; else i += 4; } else if (aInString[PRUint32(i) + 1] == '!' && aInString[PRUint32(i) + 2] == '-' && aInString[PRUint32(i) + 3] == '-') //if out-commended code, skip until --> { i = aInString.Find("-->", false, i); if (i == kNotFound) i = lengthOfInString; else i += 3; } else // just skip tag (attributes etc.) { i = aInString.FindChar('>', i); if (i == kNotFound) i = lengthOfInString; else i++; } aOutString.Append(&uniBuffer[start], PRUint32(i) - start); } else { PRUint32 start = PRUint32(i); i = aInString.FindChar('<', i); if (i == kNotFound) i = lengthOfInString; nsString tempString; tempString.SetCapacity(PRUint32((PRUint32(i) - start) * growthRate)); UnescapeStr(uniBuffer, start, PRUint32(i) - start, tempString); ScanTXT(tempString.get(), tempString.Length(), whattodo, aOutString); } } #ifdef DEBUG_BenB_Perf printf("ScanHTML time: %d ms\n", PR_IntervalToMilliseconds(PR_IntervalNow() - parsing_start)); #endif }
extern "C" PRUint32 invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) { return PRUint32(((paramCount * 2) + 3) & ~3); }
NS_IMETHODIMP nsScriptPaginator::AdjustPageBreaks () { // Update less frequently if we're not in the middle of pagination if ((mUpdateCount++ % 5) != 0 && ! mNextPageStartsAt) return NS_OK; PRInt32 modificationCount; mEditor->GetModificationCount(&modificationCount); if (modificationCount == mModificationCount) return NS_OK; mModificationCount = modificationCount; nsCOMPtr<nsIDOMXPathEvaluator> xpe = do_CreateInstance( "@mozilla.org/dom/xpath-evaluator;1"); nsCOMPtr<nsIDOMXPathResult> result; nsresult rv = xpe->Evaluate( NS_LITERAL_STRING("//div[@class='softbreak' or @class='hardbreak']"), mScript, nsnull, nsIDOMXPathResult::ORDERED_NODE_ITERATOR_TYPE, nsnull, getter_AddRefs(result)); if (NS_FAILED(rv)) return rv; // |lastbreak| stores the last known correct page break nsCOMPtr<nsIDOMNSHTMLElement> lastbreak; nsCOMPtr<nsIDOMNSHTMLElement> pagebreak; PRUint32 breaknum = 0; // Determine where the first adjustment needs to be made nsCOMPtr<nsIDOMNode> cursor; rv = result->IterateNext(getter_AddRefs(cursor)); while (NS_SUCCEEDED(rv) && cursor) { pagebreak = do_QueryInterface(cursor); if (pagebreak) { PRInt32 offset = 0; pagebreak->GetOffsetTop(&offset); if (breaknum >= mPageBreakOffsets.Length() || PRUint32(offset) != mPageBreakOffsets[breaknum]) break; lastbreak = pagebreak; ++breaknum; } rv = result->IterateNext(getter_AddRefs(cursor)); } if (NS_FAILED(rv)) return rv; // We're starting from scratch, might as well confirm font metrics if (! mNextPageStartsAt) CalculateFontMetrics(); // Adjust all the way to the end, or until enough time has passed if (lastbreak) { nsCOMPtr<nsIDOMNode> lastbreaknode(do_QueryInterface(lastbreak)); lastbreaknode->GetNextSibling(getter_AddRefs(cursor)); } else { nsCOMPtr<nsIDOMHTMLDocument> hdoc(do_QueryInterface(mScript)); nsCOMPtr<nsIDOMHTMLElement> body; hdoc->GetBody(getter_AddRefs(body)); body->GetFirstChild(getter_AddRefs(cursor)); } PRUint16 nodeType = 0; while (cursor) { cursor->GetNodeType(&nodeType); if (nodeType == nsIDOMNode::ELEMENT_NODE) break; nsCOMPtr<nsIDOMNode> tmp; cursor->GetNextSibling(getter_AddRefs(tmp)); cursor = tmp; } mNextPageStartsAt = cursor; mCurPageBreakNum = breaknum; nsTime start; nsTime end = start + nsTime(500000); mEditor->BeginTransaction(); while (mNextPageStartsAt && nsTime() < end) { AdjustNextPageBreak(); } mEditor->EndTransaction(); mPageCount = mPageBreakOffsets.Length() + 1; mLastPaginationEnded = nsTime(); return NS_OK; }
// called on the socket thread nsresult nsHttpTransaction::HandleContent(char *buf, PRUint32 count, PRUint32 *contentRead, PRUint32 *contentRemaining) { nsresult rv; LOG(("nsHttpTransaction::HandleContent [this=%x count=%u]\n", this, count)); *contentRead = 0; *contentRemaining = 0; NS_ASSERTION(mConnection, "no connection"); if (!mDidContentStart) { rv = HandleContentStart(); if (NS_FAILED(rv)) return rv; // Do not write content to the pipe if we haven't started streaming yet if (!mDidContentStart) return NS_OK; } if (mChunkedDecoder) { // give the buf over to the chunked decoder so it can reformat the // data and tell us how much is really there. rv = mChunkedDecoder->HandleChunkedContent(buf, count, contentRead, contentRemaining); if (NS_FAILED(rv)) return rv; } else if (mContentLength >= PRInt64(0)) { // HTTP/1.0 servers have been known to send erroneous Content-Length // headers. So, unless the connection is persistent, we must make // allowances for a possibly invalid Content-Length header. Thus, if // NOT persistent, we simply accept everything in |buf|. if (mConnection->IsPersistent() || mPreserveStream) { PRInt64 remaining = mContentLength - mContentRead; *contentRead = PRUint32(NS_MIN<PRInt64>(count, remaining)); *contentRemaining = count - *contentRead; } else { *contentRead = count; // mContentLength might need to be increased... PRInt64 position = mContentRead + PRInt64(count); if (position > mContentLength) { mContentLength = position; //mResponseHead->SetContentLength(mContentLength); } } } else { // when we are just waiting for the server to close the connection... // (no explicit content-length given) *contentRead = count; } if (*contentRead) { // update count of content bytes read and report progress... mContentRead += *contentRead; /* when uncommenting, take care of 64-bit integers w/ NS_MAX... if (mProgressSink) mProgressSink->OnProgress(nsnull, nsnull, mContentRead, NS_MAX(0, mContentLength)); */ } LOG(("nsHttpTransaction::HandleContent [this=%x count=%u read=%u mContentRead=%lld mContentLength=%lld]\n", this, count, *contentRead, mContentRead, mContentLength)); // check for end-of-file if ((mContentRead == mContentLength) || (mChunkedDecoder && mChunkedDecoder->ReachedEOF())) { // the transaction is done with a complete response. mTransactionDone = PR_TRUE; mResponseIsComplete = PR_TRUE; // report the entire response has arrived if (mActivityDistributor) mActivityDistributor->ObserveActivity( mChannel, NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION, NS_HTTP_ACTIVITY_SUBTYPE_RESPONSE_COMPLETE, PR_Now(), static_cast<PRUint64>(mContentRead), EmptyCString()); } return NS_OK; }
void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { /* int number_passes; NOT USED */ png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; unsigned int channels; png_bytep trans = NULL; int num_trans = 0; nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr)); /* always decode to 24-bit RGB or 32-bit RGBA */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); /* Are we too big? */ if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) longjmp(png_jmpbuf(decoder->mPNG), 1); // Post our size to the superclass decoder->PostSize(width, height); if (decoder->HasError()) { // Setting the size lead to an error; this can happen when for example // a multipart channel sends an image of a different size. longjmp(png_jmpbuf(decoder->mPNG), 1); } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { int sample_max = (1 << bit_depth); png_color_16p trans_values; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); /* libpng doesn't reject a tRNS chunk with out-of-range samples so we check it here to avoid setting up a useless opacity channel or producing unexpected transparent pixels when using libpng-1.2.19 through 1.2.26 (bug #428045) */ if ((color_type == PNG_COLOR_TYPE_GRAY && (int)trans_values->gray > sample_max) || (color_type == PNG_COLOR_TYPE_RGB && ((int)trans_values->red > sample_max || (int)trans_values->green > sample_max || (int)trans_values->blue > sample_max))) { /* clear the tRNS valid flag and release tRNS memory */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); } else png_set_expand(png_ptr); } if (bit_depth == 16) png_set_strip_16(png_ptr); qcms_data_type inType; PRUint32 intent = -1; PRUint32 pIntent; if (decoder->mCMSMode != eCMSMode_Off) { intent = gfxPlatform::GetRenderingIntent(); decoder->mInProfile = PNGGetColorProfile(png_ptr, info_ptr, color_type, &inType, &pIntent); /* If we're not mandating an intent, use the one from the image. */ if (intent == PRUint32(-1)) intent = pIntent; } if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) { qcms_data_type outType; if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) outType = QCMS_DATA_RGBA_8; else outType = QCMS_DATA_RGB_8; decoder->mTransform = qcms_transform_create(decoder->mInProfile, inType, gfxPlatform::GetCMSOutputProfile(), outType, (qcms_intent)intent); } else { png_set_gray_to_rgb(png_ptr); // only do gamma correction if CMS isn't entirely disabled if (decoder->mCMSMode != eCMSMode_Off) PNGDoGammaCorrection(png_ptr, info_ptr); if (decoder->mCMSMode == eCMSMode_All) { if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) decoder->mTransform = gfxPlatform::GetCMSRGBATransform(); else decoder->mTransform = gfxPlatform::GetCMSRGBTransform(); } } /* let libpng expand interlaced images */ if (interlace_type == PNG_INTERLACE_ADAM7) { /* number_passes = */ png_set_interlace_handling(png_ptr); } /* now all of those things we set above are used to update various struct * members and whatnot, after which we can get channels, rowbytes, etc. */ png_read_update_info(png_ptr, info_ptr); decoder->mChannels = channels = png_get_channels(png_ptr, info_ptr); /*---------------------------------------------------------------*/ /* copy PNG info into imagelib structs (formerly png_set_dims()) */ /*---------------------------------------------------------------*/ PRInt32 alpha_bits = 1; if (channels == 2 || channels == 4) { /* check if alpha is coming from a tRNS chunk and is binary */ if (num_trans) { /* if it's not an indexed color image, tRNS means binary */ if (color_type == PNG_COLOR_TYPE_PALETTE) { for (int i=0; i<num_trans; i++) { if ((trans[i] != 0) && (trans[i] != 255)) { alpha_bits = 8; break; } } } } else { alpha_bits = 8; } } if (channels == 1 || channels == 3) decoder->format = gfxASurface::ImageFormatRGB24; else if (channels == 2 || channels == 4) decoder->format = gfxASurface::ImageFormatARGB32; #ifdef PNG_APNG_SUPPORTED if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) png_set_progressive_frame_fn(png_ptr, nsPNGDecoder::frame_info_callback, NULL); if (png_get_first_frame_is_hidden(png_ptr, info_ptr)) { decoder->mFrameIsHidden = PR_TRUE; } else { #endif decoder->CreateFrame(0, 0, width, height, decoder->format); #ifdef PNG_APNG_SUPPORTED } #endif if (decoder->mTransform && (channels <= 2 || interlace_type == PNG_INTERLACE_ADAM7)) { PRUint32 bpp[] = { 0, 3, 4, 3, 4 }; decoder->mCMSLine = (PRUint8 *)moz_malloc(bpp[channels] * width); if (!decoder->mCMSLine) { longjmp(png_jmpbuf(decoder->mPNG), 5); // NS_ERROR_OUT_OF_MEMORY } } if (interlace_type == PNG_INTERLACE_ADAM7) { if (height < PR_INT32_MAX / (width * channels)) decoder->interlacebuf = (PRUint8 *)moz_malloc(channels * width * height); if (!decoder->interlacebuf) { longjmp(png_jmpbuf(decoder->mPNG), 5); // NS_ERROR_OUT_OF_MEMORY } } /* Reject any ancillary chunk after IDAT with a bad CRC (bug #397593). * It would be better to show the default frame (if one has already been * successfully decoded) before bailing, but it's simpler to just bail * out with an error message. */ png_set_crc_action(png_ptr, PNG_CRC_NO_CHANGE, PNG_CRC_ERROR_QUIT); return; }
// This needs vast improvement static PRBool ucIsAlpha(PRUnichar c) { // XXX we have to fix callers to handle the full Unicode range return (5 == GetCat(PRUint32(c))); }
NS_IMETHODIMP ContinueRunnable::Run() { nsresult rv; if (!NS_IsMainThread()) { rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } // Remove cached stuff from last time. mCursor->mCachedKey = nsnull; mCursor->mCachedValue = JSVAL_VOID; mCursor->mHaveCachedValue = false; mCursor->mContinueCalled = false; if (mCursor->mType == IDBCursor::INDEX) { mCursor->mKeyData.RemoveElementAt(mCursor->mDataIndex); } else { mCursor->mData.RemoveElementAt(mCursor->mDataIndex); } if (mCursor->mDataIndex) { mCursor->mDataIndex--; } nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID); if (!variant) { NS_ERROR("Couldn't create variant!"); return NS_ERROR_FAILURE; } PRBool empty = mCursor->mType == IDBCursor::INDEX ? mCursor->mKeyData.IsEmpty() : mCursor->mData.IsEmpty(); if (empty) { rv = variant->SetAsEmpty(); NS_ENSURE_SUCCESS(rv, rv); } else { if (!mKey.IsUnset()) { NS_ASSERTION(!mKey.IsNull(), "Huh?!"); NS_WARNING("Using a slow O(n) search for continue(key), do something " "smarter!"); // Skip ahead to our next key match. PRInt32 index = PRInt32(mCursor->mDataIndex); if (mCursor->mType == IDBCursor::INDEX) { while (index >= 0) { const Key& key = mCursor->mKeyData[index].key; if (mKey == key) { break; } if (key < mKey) { index--; continue; } index = -1; break; } if (index >= 0) { mCursor->mDataIndex = PRUint32(index); mCursor->mKeyData.RemoveElementsAt(index + 1, mCursor->mKeyData.Length() - index - 1); } } else { while (index >= 0) { const Key& key = mCursor->mData[index].key; if (mKey == key) { break; } if (key < mKey) { index--; continue; } index = -1; break; } if (index >= 0) { mCursor->mDataIndex = PRUint32(index); mCursor->mData.RemoveElementsAt(index + 1, mCursor->mData.Length() - index - 1); } } } rv = variant->SetAsISupports(static_cast<IDBRequest::Generator*>(mCursor)); NS_ENSURE_SUCCESS(rv, rv); } rv = variant->SetWritable(PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMEvent> event = IDBSuccessEvent::Create(mCursor->mRequest, variant, mCursor->mTransaction); if (!event) { NS_ERROR("Failed to create event!"); return NS_ERROR_FAILURE; } PRBool dummy; mCursor->mRequest->DispatchEvent(event, &dummy); mCursor->mTransaction->OnRequestFinished(); mCursor = nsnull; return NS_OK; }
static int X11Error(Display *display, XErrorEvent *event) { // Get an indication of how long ago the request that caused the error was // made. unsigned long age = NextRequest(display) - event->serial; // Get a string to represent the request that caused the error. nsCAutoString message; if (event->request_code < 128) { // Core protocol request message.AppendInt(event->request_code); } else { // Extension request // man XSetErrorHandler says "the error handler should not call any // functions (directly or indirectly) on the display that will generate // protocol requests or that will look for input events" so we use another // temporary Display to request extension information. This assumes on // the DISPLAY environment variable has been set and matches what was used // to open |display|. Display *tmpDisplay = XOpenDisplay(NULL); if (tmpDisplay) { int nExts; char** extNames = XListExtensions(tmpDisplay, &nExts); int first_error; if (extNames) { for (int i = 0; i < nExts; ++i) { int major_opcode, first_event; if (XQueryExtension(tmpDisplay, extNames[i], &major_opcode, &first_event, &first_error) && major_opcode == event->request_code) { message.Append(extNames[i]); message.Append('.'); message.AppendInt(event->minor_code); break; } } XFreeExtensionList(extNames); } XCloseDisplay(tmpDisplay); #ifdef MOZ_WIDGET_GTK2 // GDK2 calls XCloseDevice the devices that it opened on startup, but // the XI protocol no longer ensures that the devices will still exist. // If they have been removed, then a BadDevice error results. Ignore // this error. if (message.EqualsLiteral("XInputExtension.4") && event->error_code == first_error + 0) { return 0; } #endif } } char buffer[BUFSIZE]; if (message.IsEmpty()) { buffer[0] = '\0'; } else { XGetErrorDatabaseText(display, "XRequest", message.get(), "", buffer, sizeof(buffer)); } nsCAutoString notes; if (buffer[0]) { notes.Append(buffer); } else { notes.Append("Request "); notes.AppendInt(event->request_code); notes.Append('.'); notes.AppendInt(event->minor_code); } notes.Append(": "); // Get a string to describe the error. XGetErrorText(display, event->error_code, buffer, sizeof(buffer)); notes.Append(buffer); // For requests where Xlib gets the reply synchronously, |age| will be 1 // and the stack will include the function making the request. For // asynchronous requests, the current stack will often be unrelated to the // point of making the request, even if |age| is 1, but sometimes this may // help us count back to the point of the request. With XSynchronize on, // the stack will include the function making the request, even though // |age| will be 2 for asynchronous requests because XSynchronize is // implemented by an empty request from an XSync, which has not yet been // processed. if (age > 1) { // XSynchronize returns the previous "after function". If a second // XSynchronize call returns the same function after an enable call then // synchronization must have already been enabled. if (XSynchronize(display, True) == XSynchronize(display, False)) { notes.Append("; sync"); } else { notes.Append("; "); notes.AppendInt(PRUint32(age)); notes.Append(" requests ago"); } } #ifdef MOZ_CRASHREPORTER switch (XRE_GetProcessType()) { case GeckoProcessType_Default: case GeckoProcessType_Plugin: case GeckoProcessType_Content: CrashReporter::AppendAppNotesToCrashReport(notes); break; default: ; // crash report notes not supported. } #endif #ifdef DEBUG // The resource id is unlikely to be useful in a crash report without // context of other ids, but add it to the debug console output. notes.Append("; id=0x"); notes.AppendInt(PRUint32(event->resourceid), 16); #ifdef MOZ_X11 // Actually, for requests where Xlib gets the reply synchronously, // MOZ_X_SYNC=1 will not be necessary, but we don't have a table to tell us // which requests get a synchronous reply. if (!PR_GetEnv("MOZ_X_SYNC")) { notes.Append("\nRe-running with MOZ_X_SYNC=1 in the environment may give a more helpful backtrace."); } #endif #endif #ifdef MOZ_WIDGET_QT // We should not abort here if MOZ_X_SYNC is not set // until http://bugreports.qt.nokia.com/browse/QTBUG-4042 // not fixed, just print error value if (!PR_GetEnv("MOZ_X_SYNC")) { fprintf(stderr, "XError: %s\n", notes.get()); return 0; // temporary workaround for bug 161472 } #endif NS_RUNTIMEABORT(notes.get()); return 0; // not reached }
void nsPresArena::FreeBySize(size_t aSize, void* aPtr) { mState->Free(PRUint32(aSize) | PRUint32(nsQueryFrame::NON_FRAME_MARKER), aPtr); }
NS_IMETHODIMP nsScriptPaginator::AdjustSynchronously () { nsCOMPtr<nsIDOMXPathEvaluator> xpe = do_CreateInstance( "@mozilla.org/dom/xpath-evaluator;1"); nsCOMPtr<nsIDOMXPathResult> result; nsresult rv = xpe->Evaluate( NS_LITERAL_STRING("//div[@class='softbreak' or @class='hardbreak']"), mScript, nsnull, nsIDOMXPathResult::ORDERED_NODE_ITERATOR_TYPE, nsnull, getter_AddRefs(result)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIDOMNSHTMLElement> lastbreak; nsCOMPtr<nsIDOMNSHTMLElement> pagebreak; nsCOMPtr<nsIDOMNode> cursor; PRUint32 breaknum = 0; rv = result->IterateNext(getter_AddRefs(cursor)); while (NS_SUCCEEDED(rv) && cursor) { pagebreak = do_QueryInterface(cursor); if (pagebreak) { PRInt32 offset = 0; pagebreak->GetOffsetTop(&offset); if (breaknum >= mPageBreakOffsets.Length() || PRUint32(offset) != mPageBreakOffsets[breaknum]) break; lastbreak = pagebreak; ++breaknum; } rv = result->IterateNext(getter_AddRefs(cursor)); } if (NS_FAILED(rv)) return rv; CalculateFontMetrics(); // Adjust from the last valid page break (or the start) onwards if (lastbreak) { nsCOMPtr<nsIDOMNode> lastbreaknode(do_QueryInterface(lastbreak)); lastbreaknode->GetNextSibling(getter_AddRefs(cursor)); } else { nsCOMPtr<nsIDOMHTMLDocument> hdoc(do_QueryInterface(mScript)); hdoc->GetFirstChild(getter_AddRefs(cursor)); } PRUint16 nodeType = 0; while (cursor) { cursor->GetNodeType(&nodeType); if (nodeType == nsIDOMNode::ELEMENT_NODE) break; nsCOMPtr<nsIDOMNode> tmp; cursor->GetNextSibling(getter_AddRefs(tmp)); cursor = tmp; } mNextPageStartsAt = cursor; mCurPageBreakNum = breaknum; mEditor->BeginTransaction(); while (mNextPageStartsAt) AdjustNextPageBreak(); mEditor->EndTransaction(); mPageCount = mPageBreakOffsets.Length() + 1; mLastPaginationEnded = nsTime(); return NS_OK; }
nsresult nsMemoryCacheDevice::EvictEntries(const char * clientID) { ClientIDArgs args = {clientID, clientID ? PRUint32(strlen(clientID)) : 0}; return DoEvictEntries(&EntryMatchesClientID, &args); }
void nsScriptPaginator::AdjustNextPageBreak () { NS_NAMED_LITERAL_STRING(kClassStr, "class"); NS_NAMED_LITERAL_STRING(kSoftBreakStr, "softbreak"); NS_NAMED_LITERAL_STRING(kHardBreakStr, "hardbreak"); NS_NAMED_LITERAL_STRING(kActStr, "act"); NS_NAMED_LITERAL_STRING(kDivStr, "div"); // Allow an extra line per page to accommodate bottom margins const PRInt32 kPageHeight = PRInt32(mLineHeight * (mLinesPerPage + 1)); nsCOMPtr<nsIDOMNode> node = mNextPageStartsAt; if (! node) { nsCOMPtr<nsIDOMHTMLDocument> hdoc(do_QueryInterface(mScript)); nsCOMPtr<nsIDOMHTMLElement> body; hdoc->GetBody(getter_AddRefs(body)); if (! body) { return; } body->GetFirstChild(getter_AddRefs(node)); mCurPageBreakNum = 0; if (! node) { return; } } nsCOMPtr<nsIDOMNSHTMLElement> element(do_QueryInterface(node)); if (! element) return; PRInt32 offset = 0; element->GetOffsetTop(&offset); PRUint32 pageEnd = PRUint32(offset + kPageHeight); nsCOMPtr<nsIDOMNSHTMLElement> innerBreak(nsnull); // Adjust for height of page break if we start at one nsString className; { nsCOMPtr<nsIDOMElement> elemnode(do_QueryInterface(node)); elemnode->GetAttribute(kClassStr, className); if (className.Equals(kSoftBreakStr) || className.Equals(kHardBreakStr)) { PRInt32 height; element->GetClientHeight(&height); pageEnd += height; } } // Basic strategy: // 1. Get the next node // 2. If the next node is undefined // 2.1. If the page break cache extends further // 2.1.1. Splice the remaining page breaks // 2.2. Exit // 3. Else if the next node is a hard break (or act) // 3.1. Advance the page cursor // 3.2. Exit // 4. Else if the next node is a soft break // 4.1. If a soft break is cached as |innerBreak| // 4.1.1. Remove |innerBreak| // 4.2. Cache the node as |innerBreak| // 5. Else if the node does not fit the page // 5.1. Find the last node (inclusive) that allows a break before it // 5.2. If a soft break is cached as |innerBreak| // 5.2.1. If |innerBreak| occurs as the previous sibling to the last node // 5.2.1.1. Advance the page cursor // 5.2.1.2. Exit // 5.2.2. Else // 5.2.2.1. Remove |innerBreak| // 5.2.2.2. Insert a new soft page break // 5.2.2.3. Advance the page cursor // 5.2.2.4. Exit // 5.3. Else // 5.3.1. Insert a new soft page break // 5.3.2. Advance the page cursor // 5.3.3. Exit // 6. Else // 6.1. Continue nsCOMPtr<nsIDOMNode> tmpnode; PRUint16 nodeType = 0; nsCOMPtr<nsIDOMNode> elemnode(do_QueryInterface(element)); elemnode->GetNextSibling(getter_AddRefs(tmpnode)); if (tmpnode) tmpnode->GetNodeType(&nodeType); while (tmpnode && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; tmpnode->GetNextSibling(getter_AddRefs(tmpnode2)); tmpnode = tmpnode2; if (tmpnode) tmpnode->GetNodeType(&nodeType); } if (tmpnode) element = do_QueryInterface(tmpnode); else element = nsnull; while (element) { nsCOMPtr<nsIDOMElement> elemnode(do_QueryInterface(element)); elemnode->GetAttribute(kClassStr, className); element->GetOffsetTop(&offset); // If it's an act, make sure it's got a page break before it, unless // it's the first element in the script. if (className.Equals(kActStr)) { // Get the previous element to this act that isn't a page break elemnode->GetPreviousSibling(getter_AddRefs(tmpnode)); /* if (tmpnode) tmpnode->GetNodeType(&nodeType); while (tmpnode && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; tmpnode->GetPreviousSibling(getter_AddRefs(tmpnode2)); tmpnode = tmpnode2; if (tmpnode) tmpnode->GetNodeType(&nodeType); } */ while (tmpnode) { nsCOMPtr<nsIDOMHTMLParagraphElement> para(do_QueryInterface(tmpnode)); if (para) break; nsCOMPtr<nsIDOMNode> tmpnode2; tmpnode->GetPreviousSibling(getter_AddRefs(tmpnode2)); tmpnode = tmpnode2; } nsCOMPtr<nsIDOMElement> prev(do_QueryInterface(tmpnode)); // If no previous element, then this isn't important if (prev) { // Otherwise, make sure the act is preceded by a page break prev->GetAttribute(kClassStr, className); if (! className.Equals(kSoftBreakStr) && ! className.Equals(kHardBreakStr)) { // Make a break! nsCOMPtr<nsIDOMElement> breaknode; mScript->CreateElement(kDivStr, getter_AddRefs(breaknode)); prev = do_QueryInterface(breaknode); prev->SetAttribute(kClassStr, kSoftBreakStr); nsCOMPtr<nsIDOMText> text; mScript->CreateTextNode(NS_LITERAL_STRING(" "), getter_AddRefs(text)); nsCOMPtr<nsIDOMNode> dummy; prev->AppendChild(text, getter_AddRefs(dummy)); nsCOMPtr<nsIDOMNode> parent; elemnode->GetParentNode(getter_AddRefs(parent)); parent->InsertBefore(prev, elemnode, getter_AddRefs(dummy)); } nsCOMPtr<nsIDOMNSHTMLElement> htmlprev(do_QueryInterface(prev)); htmlprev->GetOffsetTop(&offset); if (mCurPageBreakNum >= mPageBreakOffsets.Length()) mPageBreakOffsets.AppendElement((PRUint32) offset); else mPageBreakOffsets[mCurPageBreakNum] = (PRUint32) offset; ++mCurPageBreakNum; mNextPageStartsAt = do_QueryInterface(element); return; } } // Hard breaks don't move. Just record the offset and keep going. if (className.Equals(kHardBreakStr)) { element->GetOffsetTop(&offset); if (mCurPageBreakNum >= mPageBreakOffsets.Length()) mPageBreakOffsets.AppendElement(offset); else mPageBreakOffsets[mCurPageBreakNum] = offset; ++mCurPageBreakNum; mNextPageStartsAt = do_QueryInterface(element); return; } element->GetOffsetTop(&offset); PRInt32 height; element->GetClientHeight(&height); if (className.Equals(kSoftBreakStr)) { // Soft break! Make sure it's in the right position, and eliminate // or move up any preceding soft break that isn't necessary. if (innerBreak) { // Remove the last inner break, and make this one the new inner // break. No need to adjust pageEnd, because the removed page break // balances the current page break. nsCOMPtr<nsIDOMNode> parent; nsCOMPtr<nsIDOMNode> innernode(do_QueryInterface(innerBreak)); nsCOMPtr<nsIDOMNode> dummy; innernode->GetParentNode(getter_AddRefs(parent)); parent->RemoveChild(innernode, getter_AddRefs(dummy)); } else { elemnode->GetNextSibling(getter_AddRefs(tmpnode)); if (tmpnode) tmpnode->GetNodeType(&nodeType); while (tmpnode && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; tmpnode->GetNextSibling(getter_AddRefs(tmpnode2)); tmpnode = tmpnode2; if (tmpnode) tmpnode->GetNodeType(&nodeType); } if (tmpnode) { nsCOMPtr<nsIDOMNSHTMLElement> next(do_QueryInterface(tmpnode)); PRInt32 nextOffset = 0; next->GetOffsetTop(&nextOffset); // pageEnd += PRUint32(nextOffset - offset); } } innerBreak = element; } else if (PRUint32(offset + height) > pageEnd) { // Not a soft break, but it exceeds the page length so // we need to paginate. // If we can't break here, rewind until we reach a node where we can. tmpnode = do_QueryInterface(element); while (! CanBreakBeforeNode(tmpnode) && tmpnode != mNextPageStartsAt) { nsCOMPtr<nsIDOMNode> prev; tmpnode->GetPreviousSibling(getter_AddRefs(prev)); if (! prev) break; prev->GetNodeType(&nodeType); while (prev && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; prev->GetPreviousSibling(getter_AddRefs(tmpnode2)); if (tmpnode2) tmpnode2->GetNodeType(&nodeType); prev = tmpnode2; } tmpnode = prev; } // If |tmpnode| == |mNextPageStartsAt|, we've backtracked to the // previous page. This generally happens when an element is too big // to fit on the page. Until we can break long elements in half, keep // going forward until the next opportunity to insert a break. if (tmpnode == mNextPageStartsAt) { // Set |element| to the next element elemnode->GetNextSibling(getter_AddRefs(tmpnode)); if (tmpnode) tmpnode->GetNodeType(&nodeType); while (tmpnode && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; tmpnode->GetNextSibling(getter_AddRefs(tmpnode2)); tmpnode = tmpnode2; if (tmpnode) tmpnode->GetNodeType(&nodeType); } if (tmpnode) element = do_QueryInterface(tmpnode); else element = nsnull; continue; } if (innerBreak) { // Move up the inner break to the current position (unless it's // already the previous element) nsCOMPtr<nsIDOMNode> prev; tmpnode->GetPreviousSibling(getter_AddRefs(prev)); if (! prev) break; prev->GetNodeType(&nodeType); while (prev && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; prev->GetPreviousSibling(getter_AddRefs(tmpnode2)); if (tmpnode2) tmpnode2->GetNodeType(&nodeType); prev = tmpnode2; } nsCOMPtr<nsIDOMNode> innernode(do_QueryInterface(innerBreak)); if (prev != innernode) { nsCOMPtr<nsIDOMNode> parent; tmpnode->GetParentNode(getter_AddRefs(parent)); nsCOMPtr<nsIDOMNode> dummy; parent->InsertBefore(innernode, tmpnode, getter_AddRefs(dummy)); } } else { nsCOMPtr<nsIDOMElement> pagebreak; mScript->CreateElement(kDivStr, getter_AddRefs(pagebreak)); pagebreak->SetAttribute(kClassStr, kSoftBreakStr); nsCOMPtr<nsIDOMText> text; nsCOMPtr<nsIDOMNode> dummy; mScript->CreateTextNode(NS_LITERAL_STRING(" "), getter_AddRefs(text)); pagebreak->AppendChild(text, getter_AddRefs(dummy)); nsCOMPtr<nsIDOMNode> parent; tmpnode->GetParentNode(getter_AddRefs(parent)); parent->InsertBefore(pagebreak, tmpnode, getter_AddRefs(dummy)); innerBreak = do_QueryInterface(pagebreak); } innerBreak->GetOffsetTop(&offset); if (mCurPageBreakNum >= mPageBreakOffsets.Length()) mPageBreakOffsets.AppendElement(offset); else mPageBreakOffsets[mCurPageBreakNum] = offset; ++mCurPageBreakNum; mNextPageStartsAt = tmpnode; return; } // set |element| to the next element // Man does XPCOM make some conventions difficult! e.g., expressing // while (element = element.nextSibling && element.nodeType != ...) elemnode->GetNextSibling(getter_AddRefs(tmpnode)); if (tmpnode) tmpnode->GetNodeType(&nodeType); while (tmpnode && nodeType != nsIDOMNode::ELEMENT_NODE) { nsCOMPtr<nsIDOMNode> tmpnode2; tmpnode->GetNextSibling(getter_AddRefs(tmpnode2)); tmpnode = tmpnode2; if (tmpnode) tmpnode->GetNodeType(&nodeType); } if (tmpnode) element = do_QueryInterface(tmpnode); else element = nsnull; } // This should be guaranteed if (! element) { // Strip away any remaining page break offsets if (mPageBreakOffsets.Length() > 0 && mPageBreakOffsets.Length() > mCurPageBreakNum + 1) { mPageBreakOffsets.SetLength(mCurPageBreakNum + 1); } if (innerBreak) { nsCOMPtr<nsIDOMNode> parent; nsCOMPtr<nsIDOMNode> innernode(do_QueryInterface(innerBreak)); nsCOMPtr<nsIDOMNode> dummy; innernode->GetParentNode(getter_AddRefs(parent)); parent->RemoveChild(innernode, getter_AddRefs(dummy)); } mNextPageStartsAt = nsnull; } }
void nsHTMLContentSerializer::SerializeAttributes(nsIContent* aContent, nsIDOMElement *aOriginalElement, nsAString& aTagPrefix, const nsAString& aTagNamespaceURI, nsIAtom* aTagName, nsAString& aStr) { PRInt32 count = aContent->GetAttrCount(); if (!count) return; nsresult rv; nsAutoString nameStr, valueStr; NS_NAMED_LITERAL_STRING(_mozStr, "_moz"); // HTML5 parser stored them in the order they were parsed so we want to // loop forward in that case. nsIDocument* doc = aContent->GetOwnerDocument(); PRBool caseSensitive = doc && doc->IsCaseSensitive(); PRBool loopForward = PR_FALSE; if (!caseSensitive) { nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(doc)); if (htmlDoc) { loopForward = nsHtml5Module::sEnabled; } } PRInt32 index, limit, step; if (loopForward) { index = 0; limit = count; step = 1; } else { // Loop backward over the attributes, since the order they are stored in is // the opposite of the order they were parsed in (see bug 213347 for reason). index = count - 1; limit = -1; step = -1; } for (; index != limit; index += step) { const nsAttrName* name = aContent->GetAttrNameAt(index); PRInt32 namespaceID = name->NamespaceID(); nsIAtom* attrName = name->LocalName(); // Filter out any attribute starting with [-|_]moz const char* sharedName; attrName->GetUTF8String(&sharedName); if ((('_' == *sharedName) || ('-' == *sharedName)) && !nsCRT::strncmp(sharedName+1, kMozStr, PRUint32(sizeof(kMozStr)-1))) { continue; } aContent->GetAttr(namespaceID, attrName, valueStr); // // Filter out special case of <br type="_moz"> or <br _moz*>, // used by the editor. Bug 16988. Yuck. // if (aTagName == nsGkAtoms::br && attrName == nsGkAtoms::type && StringBeginsWith(valueStr, _mozStr)) { continue; } if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li) && (attrName == nsGkAtoms::value)){ // This is handled separately in SerializeLIValueAttribute() continue; } PRBool isJS = IsJavaScript(aContent, attrName, namespaceID, valueStr); if (((attrName == nsGkAtoms::href) || (attrName == nsGkAtoms::src))) { // Make all links absolute when converting only the selection: if (mFlags & nsIDocumentEncoder::OutputAbsoluteLinks) { // Would be nice to handle OBJECT and APPLET tags, // but that gets more complicated since we have to // search the tag list for CODEBASE as well. // For now, just leave them relative. nsCOMPtr<nsIURI> uri = aContent->GetBaseURI(); if (uri) { nsAutoString absURI; rv = NS_MakeAbsoluteURI(absURI, valueStr, uri); if (NS_SUCCEEDED(rv)) { valueStr = absURI; } } } // Need to escape URI. nsAutoString tempURI(valueStr); if (!isJS && NS_FAILED(EscapeURI(aContent, tempURI, valueStr))) valueStr = tempURI; } if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta && attrName == nsGkAtoms::content) { // If we're serializing a <meta http-equiv="content-type">, // use the proper value, rather than what's in the document. nsAutoString header; aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header); if (header.LowerCaseEqualsLiteral("content-type")) { valueStr = NS_LITERAL_STRING("text/html; charset=") + NS_ConvertASCIItoUTF16(mCharset); } } attrName->ToString(nameStr); // Expand shorthand attribute. if (IsShorthandAttr(attrName, aTagName) && valueStr.IsEmpty()) { valueStr = nameStr; } SerializeAttr(EmptyString(), nameStr, valueStr, aStr, !isJS); } }
PRBool gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array) { return mPrefFonts.Get(PRUint32(aLangGroup), array); }
bool mozTXTToHTMLConv::FindURLStart(const PRUnichar * aInString, PRInt32 aInLength, const PRUint32 pos, const modetype check, PRUint32& start) { switch(check) { // no breaks, because end of blocks is never reached case RFC1738: { if (!nsCRT::strncmp(&aInString[MaxInt(pos - 4, 0)], NS_LITERAL_STRING("<URL:").get(), 5)) { start = pos + 1; return true; } else return false; } case RFC2396E: { nsString temp(aInString, aInLength); PRInt32 i = pos <= 0 ? kNotFound : temp.RFindCharInSet(NS_LITERAL_STRING("<>\"").get(), pos - 1); if (i != kNotFound && (temp[PRUint32(i)] == '<' || temp[PRUint32(i)] == '"')) { start = PRUint32(++i); return start < pos; } else return false; } case freetext: { PRInt32 i = pos - 1; for (; i >= 0 && ( nsCRT::IsAsciiAlpha(aInString[PRUint32(i)]) || nsCRT::IsAsciiDigit(aInString[PRUint32(i)]) || aInString[PRUint32(i)] == '+' || aInString[PRUint32(i)] == '-' || aInString[PRUint32(i)] == '.' ); i--) ; if (++i >= 0 && PRUint32(i) < pos && nsCRT::IsAsciiAlpha(aInString[PRUint32(i)])) { start = PRUint32(i); return true; } else return false; } case abbreviated: { PRInt32 i = pos - 1; // This disallows non-ascii-characters for email. // Currently correct, but revisit later after standards changed. bool isEmail = aInString[pos] == (PRUnichar)'@'; // These chars mark the start of the URL for (; i >= 0 && aInString[PRUint32(i)] != '>' && aInString[PRUint32(i)] != '<' && aInString[PRUint32(i)] != '"' && aInString[PRUint32(i)] != '\'' && aInString[PRUint32(i)] != '`' && aInString[PRUint32(i)] != ',' && aInString[PRUint32(i)] != '{' && aInString[PRUint32(i)] != '[' && aInString[PRUint32(i)] != '(' && aInString[PRUint32(i)] != '|' && aInString[PRUint32(i)] != '\\' && !IsSpace(aInString[PRUint32(i)]) && (!isEmail || nsCRT::IsAscii(aInString[PRUint32(i)])) ; i--) ; if ( ++i >= 0 && PRUint32(i) < pos && ( nsCRT::IsAsciiAlpha(aInString[PRUint32(i)]) || nsCRT::IsAsciiDigit(aInString[PRUint32(i)]) ) ) { start = PRUint32(i); return true; } else return false; } default: return false; } //switch }
void gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array) { mPrefFonts.Put(PRUint32(aLangGroup), array); }
NS_IMETHODIMP nsIncrementalDownload::OnStartRequest(nsIRequest *request, nsISupports *context) { nsresult rv; nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(request, &rv); if (NS_FAILED(rv)) return rv; // Ensure that we are receiving a 206 response. PRUint32 code; rv = http->GetResponseStatus(&code); if (NS_FAILED(rv)) return rv; if (code != 206) { // We may already have the entire file downloaded, in which case // our request for a range beyond the end of the file would have // been met with an error response code. if (code == 416 && mTotalSize == PRInt64(-1)) { mTotalSize = mCurrentSize; // Return an error code here to suppress OnDataAvailable. return NS_ERROR_DOWNLOAD_COMPLETE; } // The server may have decided to give us all of the data in one chunk. If // we requested a partial range, then we don't want to download all of the // data at once. So, we'll just try again, but if this keeps happening then // we'll eventually give up. if (code == 200) { if (mInterval) { mChannel = nsnull; if (++mNonPartialCount > MAX_RETRY_COUNT) { NS_WARNING("unable to fetch a byte range; giving up"); return NS_ERROR_FAILURE; } // Increase delay with each failure. StartTimer(mInterval * mNonPartialCount); return NS_ERROR_DOWNLOAD_NOT_PARTIAL; } // Since we have been asked to download the rest of the file, we can deal // with a 200 response. This may result in downloading the beginning of // the file again, but that can't really be helped. } else { NS_WARNING("server response was unexpected"); return NS_ERROR_UNEXPECTED; } } else { // We got a partial response, so clear this counter in case the next chunk // results in a 200 response. mNonPartialCount = 0; } // Do special processing after the first response. if (mTotalSize == PRInt64(-1)) { // Update knowledge of mFinalURI rv = http->GetURI(getter_AddRefs(mFinalURI)); if (NS_FAILED(rv)) return rv; if (code == 206) { // OK, read the Content-Range header to determine the total size of this // download file. nsCAutoString buf; rv = http->GetResponseHeader(NS_LITERAL_CSTRING("Content-Range"), buf); if (NS_FAILED(rv)) return rv; PRInt32 slash = buf.FindChar('/'); if (slash == kNotFound) { NS_WARNING("server returned invalid Content-Range header!"); return NS_ERROR_UNEXPECTED; } if (PR_sscanf(buf.get() + slash + 1, "%lld", (PRInt64 *) &mTotalSize) != 1) return NS_ERROR_UNEXPECTED; } else { // Use nsIPropertyBag2 to fetch the content length as it exposes the // value as a 64-bit number. nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(request, &rv); if (NS_FAILED(rv)) return rv; rv = props->GetPropertyAsInt64(NS_CHANNEL_PROP_CONTENT_LENGTH, &mTotalSize); // We need to know the total size of the thing we're trying to download. if (mTotalSize == PRInt64(-1)) { NS_WARNING("server returned no content-length header!"); return NS_ERROR_UNEXPECTED; } // Need to truncate (or create, if it doesn't exist) the file since we // are downloading the whole thing. WriteToFile(mDest, nsnull, 0, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE); mCurrentSize = 0; } // Notify observer that we are starting... rv = CallOnStartRequest(); if (NS_FAILED(rv)) return rv; } // Adjust mChunkSize accordingly if mCurrentSize is close to mTotalSize. PRInt64 diff = mTotalSize - mCurrentSize; if (diff <= PRInt64(0)) { NS_WARNING("about to set a bogus chunk size; giving up"); return NS_ERROR_UNEXPECTED; } if (diff < PRInt64(mChunkSize)) mChunkSize = PRUint32(diff); mChunk = new char[mChunkSize]; if (!mChunk) rv = NS_ERROR_OUT_OF_MEMORY; return rv; }
#include "nsIDOMDocument.h" #include "nsIDOMNode.h" #include "nsIDOMElement.h" #include "nsIDOMProcessingInstruction.h" #include "nsINodeInfo.h" #include "nsPrintfCString.h" #include "nsReadableUtils.h" #include "nsString.h" #include "nsTextFragment.h" #include "txXMLUtils.h" #include "txLog.h" #include "nsUnicharUtils.h" #include "nsAttrName.h" #include "nsTArray.h" const PRUint32 kUnknownIndex = PRUint32(-1); txXPathTreeWalker::txXPathTreeWalker(const txXPathTreeWalker& aOther) : mPosition(aOther.mPosition), mCurrentIndex(aOther.mCurrentIndex) { } txXPathTreeWalker::txXPathTreeWalker(const txXPathNode& aNode) : mPosition(aNode), mCurrentIndex(kUnknownIndex) { } void txXPathTreeWalker::moveToRoot()
bool gfxUniscribeShaper::ShapeWord(gfxContext *aContext, gfxShapedWord *aShapedWord, const PRUnichar *aString) { DCFromContext aDC(aContext); bool result = true; HRESULT rv; Uniscribe us(aString, aShapedWord); /* itemize the string */ int numItems = us.Itemize(); PRUint32 length = aShapedWord->Length(); SaveDC(aDC); PRUint32 ivs = 0; for (int i = 0; i < numItems; ++i) { int iCharPos = us.ScriptItem(i)->iCharPos; int iCharPosNext = us.ScriptItem(i+1)->iCharPos; if (ivs) { iCharPos += 2; if (iCharPos >= iCharPosNext) { ivs = 0; continue; } } if (i+1 < numItems && iCharPosNext <= length - 2 && aString[iCharPosNext] == H_SURROGATE(kUnicodeVS17) && PRUint32(aString[iCharPosNext + 1]) - L_SURROGATE(kUnicodeVS17) <= L_SURROGATE(kUnicodeVS256) - L_SURROGATE(kUnicodeVS17)) { ivs = SURROGATE_TO_UCS4(aString[iCharPosNext], aString[iCharPosNext + 1]); } else { ivs = 0; } UniscribeItem item(aContext, aDC, this, aString + iCharPos, iCharPosNext - iCharPos, us.ScriptItem(i), ivs); if (!item.AllocateBuffers()) { result = false; break; } if (!item.ShapingEnabled()) { item.EnableShaping(); } rv = item.Shape(); if (FAILED(rv)) { // we know we have the glyphs to display this font already // so Uniscribe just doesn't know how to shape the script. // Render the glyphs without shaping. item.DisableShaping(); rv = item.Shape(); } #ifdef DEBUG if (FAILED(rv)) { NS_WARNING("Uniscribe failed to shape with font"); } #endif if (SUCCEEDED(rv)) { rv = item.Place(); #ifdef DEBUG if (FAILED(rv)) { // crap fonts may fail when placing (e.g. funky free fonts) NS_WARNING("Uniscribe failed to place with font"); } #endif } if (FAILED(rv)) { // Uniscribe doesn't like this font for some reason. // Returning FALSE will make the gfxGDIFont retry with the // "dumb" GDI shaper, unless useUniscribeOnly was set. result = false; break; } item.SaveGlyphs(aShapedWord); } RestoreDC(aDC, -1); return result; }
static inline PRBool IsWhitespace(PRInt32 ch) { return PRUint32(ch) < 256 && (gLexTable[ch] & IS_WHITESPACE) != 0; }
////////////// this needs to move to nspr static inline PRUint32 PRTimeToSeconds(PRTime t_usec) { return PRUint32(t_usec / PR_USEC_PER_SEC); }
static inline PRBool IsHexDigit(PRInt32 ch) { return PRUint32(ch) < 256 && (gLexTable[ch] & IS_HEX_DIGIT) != 0; }
NS_IMETHODIMP nsExpatDriver::ConsumeToken(nsScanner& aScanner, PRBool& aFlushTokens) { // We keep the scanner pointing to the position where Expat will start // parsing. nsScannerIterator currentExpatPosition; aScanner.CurrentPosition(currentExpatPosition); // This is the start of the first buffer that we need to pass to Expat. nsScannerIterator start = currentExpatPosition; start.advance(mExpatBuffered); // This is the end of the last buffer (at this point, more data could come in // later). nsScannerIterator end; aScanner.EndReading(end); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Remaining in expat's buffer: %i, remaining in scanner: %i.", mExpatBuffered, Distance(start, end))); // We want to call Expat if we have more buffers, or if we know there won't // be more buffers (and so we want to flush the remaining data), or if we're // currently blocked and there's data in Expat's buffer. while (start != end || (mIsFinalChunk && !mMadeFinalCallToExpat) || (BlockedOrInterrupted() && mExpatBuffered > 0)) { PRBool noMoreBuffers = start == end && mIsFinalChunk; PRBool blocked = BlockedOrInterrupted(); const PRUnichar *buffer; PRUint32 length; if (blocked || noMoreBuffers) { // If we're blocked we just resume Expat so we don't need a buffer, if // there aren't any more buffers we pass a null buffer to Expat. buffer = nsnull; length = 0; #if defined(PR_LOGGING) || defined (DEBUG) if (blocked) { PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Resuming Expat, will parse data remaining in Expat's " "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n", NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered).get())); } else { NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end), "Didn't pass all the data to Expat?"); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Last call to Expat, will parse data remaining in Expat's " "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n", NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered).get())); } #endif } else { buffer = start.get(); length = PRUint32(start.size_forward()); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Calling Expat, will parse data remaining in Expat's buffer and " "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew " "data:\n-----\n%s\n-----\n", NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered).get(), NS_ConvertUTF16toUTF8(start.get(), length).get())); } PRUint32 consumed; ParseBuffer(buffer, length, noMoreBuffers, &consumed); if (consumed > 0) { nsScannerIterator oldExpatPosition = currentExpatPosition; currentExpatPosition.advance(consumed); // We consumed some data, we want to store the last line of data that // was consumed in case we run into an error (to show the line in which // the error occurred). // The length of the last line that Expat has parsed. XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser); if (lastLineLength <= consumed) { // The length of the last line was less than what expat consumed, so // there was at least one line break in the consumed data. Store the // last line until the point where we stopped parsing. nsScannerIterator startLastLine = currentExpatPosition; startLastLine.advance(-((ptrdiff_t)lastLineLength)); CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine); } else { // There was no line break in the consumed data, append the consumed // data. AppendUnicodeTo(oldExpatPosition, currentExpatPosition, mLastLine); } } mExpatBuffered += length - consumed; if (BlockedOrInterrupted()) { PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Blocked or interrupted parser (probably for loading linked " "stylesheets or scripts).")); aScanner.SetPosition(currentExpatPosition, PR_TRUE); aScanner.Mark(); return mInternalState; } if (noMoreBuffers && mExpatBuffered == 0) { mMadeFinalCallToExpat = PR_TRUE; } if (NS_FAILED(mInternalState)) { if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) { NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING, "Unexpected error"); // Look for the next newline after the last one we consumed nsScannerIterator lastLine = currentExpatPosition; while (lastLine != end) { length = PRUint32(lastLine.size_forward()); PRUint32 endOffset = 0; const PRUnichar *buffer = lastLine.get(); while (endOffset < length && buffer[endOffset] != '\n' && buffer[endOffset] != '\r') { ++endOffset; } mLastLine.Append(Substring(buffer, buffer + endOffset)); if (endOffset < length) { // We found a newline. break; } lastLine.advance(length); } HandleError(); } return mInternalState; } // Either we have more buffers, or we were blocked (and we'll flush in the // next iteration), or we should have emptied Expat's buffer. NS_ASSERTION(!noMoreBuffers || blocked || (mExpatBuffered == 0 && currentExpatPosition == end), "Unreachable data left in Expat's buffer"); start.advance(length); // It's possible for start to have passed end if we received more data // (e.g. if we spun the event loop in an inline script). Reload end now // to compensate. aScanner.EndReading(end); } aScanner.SetPosition(currentExpatPosition, PR_TRUE); aScanner.Mark(); PR_LOG(gExpatDriverLog, PR_LOG_DEBUG, ("Remaining in expat's buffer: %i, remaining in scanner: %i.", mExpatBuffered, Distance(currentExpatPosition, end))); return NS_SUCCEEDED(mInternalState) ? kEOF : NS_OK; }
void nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) { PRUint32 length = aTextRun->GetLength(); const PRUnichar* str = aTextRun->mString.BeginReading(); nsRefPtr<nsStyleContext>* styles = aTextRun->mStyles.Elements(); nsAutoString convertedString; nsAutoTArray<bool,50> charsToMergeArray; nsAutoTArray<bool,50> deletedCharsArray; nsAutoTArray<nsStyleContext*,50> styleArray; nsAutoTArray<PRUint8,50> canBreakBeforeArray; bool mergeNeeded = false; // Some languages have special casing conventions that differ from the // default Unicode mappings. // The enum values here are named for well-known exemplar languages that // exhibit the behavior in question; multiple lang tags may map to the // same setting here, if the behavior is shared by other languages. enum { eNone, // default non-lang-specific behavior eTurkish, // preserve dotted/dotless-i distinction in uppercase eDutch, // treat "ij" digraph as a unit for capitalization eGreek // strip accent when uppercasing Greek vowels } languageSpecificCasing = eNone; const nsIAtom* lang = nullptr; bool capitalizeDutchIJ = false; bool prevIsLetter = false; PRUint32 sigmaIndex = PRUint32(-1); nsIUGenCategory::nsUGenCategory cat; GreekCasingState greekState = kStart; PRUint32 i; for (i = 0; i < length; ++i) { PRUint32 ch = str[i]; nsStyleContext* styleContext = styles[i]; PRUint8 style = mAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE : styleContext->GetStyleText()->mTextTransform; int extraChars = 0; const mozilla::unicode::MultiCharMapping *mcm; if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 && NS_IS_LOW_SURROGATE(str[i + 1])) { ch = SURROGATE_TO_UCS4(ch, str[i + 1]); } if (lang != styleContext->GetStyleFont()->mLanguage) { lang = styleContext->GetStyleFont()->mLanguage; if (lang == nsGkAtoms::tr || lang == nsGkAtoms::az || lang == nsGkAtoms::ba || lang == nsGkAtoms::crh || lang == nsGkAtoms::tt) { languageSpecificCasing = eTurkish; } else if (lang == nsGkAtoms::nl) { languageSpecificCasing = eDutch; } else if (lang == nsGkAtoms::el) { languageSpecificCasing = eGreek; greekState = kStart; } else { languageSpecificCasing = eNone; } } switch (style) { case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: if (languageSpecificCasing == eTurkish) { if (ch == 'I') { ch = LATIN_SMALL_LETTER_DOTLESS_I; prevIsLetter = true; sigmaIndex = PRUint32(-1); break; } if (ch == LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) { ch = 'i'; prevIsLetter = true; sigmaIndex = PRUint32(-1); break; } } // Special lowercasing behavior for Greek Sigma: note that this is listed // as context-sensitive in Unicode's SpecialCasing.txt, but is *not* a // language-specific mapping; it applies regardless of the language of // the element. // // The lowercase mapping for CAPITAL SIGMA should be to SMALL SIGMA (i.e. // the non-final form) whenever there is a following letter, or when the // CAPITAL SIGMA occurs in isolation (neither preceded nor followed by a // LETTER); and to FINAL SIGMA when it is preceded by another letter but // not followed by one. // // To implement the context-sensitive nature of this mapping, we keep // track of whether the previous character was a letter. If not, CAPITAL // SIGMA will map directly to SMALL SIGMA. If the previous character // was a letter, CAPITAL SIGMA maps to FINAL SIGMA and we record the // position in the converted string; if we then encounter another letter, // that FINAL SIGMA is replaced with a standard SMALL SIGMA. cat = mozilla::unicode::GetGenCategory(ch); // If sigmaIndex is not -1, it marks where we have provisionally mapped // a CAPITAL SIGMA to FINAL SIGMA; if we now find another letter, we // need to change it to SMALL SIGMA. if (sigmaIndex != PRUint32(-1)) { if (cat == nsIUGenCategory::kLetter) { convertedString.SetCharAt(GREEK_SMALL_LETTER_SIGMA, sigmaIndex); } } if (ch == GREEK_CAPITAL_LETTER_SIGMA) { // If preceding char was a letter, map to FINAL instead of SMALL, // and note where it occurred by setting sigmaIndex; we'll change it // to standard SMALL SIGMA later if another letter follows if (prevIsLetter) { ch = GREEK_SMALL_LETTER_FINAL_SIGMA; sigmaIndex = convertedString.Length(); } else { // CAPITAL SIGMA not preceded by a letter is unconditionally mapped // to SMALL SIGMA ch = GREEK_SMALL_LETTER_SIGMA; sigmaIndex = PRUint32(-1); } prevIsLetter = true; break; } // ignore diacritics for the purpose of contextual sigma mapping; // otherwise, reset prevIsLetter appropriately and clear the // sigmaIndex marker if (cat != nsIUGenCategory::kMark) { prevIsLetter = (cat == nsIUGenCategory::kLetter); sigmaIndex = PRUint32(-1); } mcm = mozilla::unicode::SpecialLower(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { convertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToLowerCase(ch); break; case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: if (languageSpecificCasing == eTurkish && ch == 'i') { ch = LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; break; } if (languageSpecificCasing == eGreek) { ch = GreekUpperCase(ch, &greekState); break; } mcm = mozilla::unicode::SpecialUpper(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { convertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToUpperCase(ch); break; case NS_STYLE_TEXT_TRANSFORM_CAPITALIZE: if (capitalizeDutchIJ && ch == 'j') { ch = 'J'; capitalizeDutchIJ = false; break; } capitalizeDutchIJ = false; if (i < aTextRun->mCapitalize.Length() && aTextRun->mCapitalize[i]) { if (languageSpecificCasing == eTurkish && ch == 'i') { ch = LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; break; } if (languageSpecificCasing == eDutch && ch == 'i') { ch = 'I'; capitalizeDutchIJ = true; break; } mcm = mozilla::unicode::SpecialTitle(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { convertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToTitleCase(ch); } break; default: break; } if (ch == PRUint32(-1)) { deletedCharsArray.AppendElement(true); mergeNeeded = true; } else { deletedCharsArray.AppendElement(false); charsToMergeArray.AppendElement(false); styleArray.AppendElement(styleContext); canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i)); if (IS_IN_BMP(ch)) { convertedString.Append(ch); } else { convertedString.Append(H_SURROGATE(ch)); convertedString.Append(L_SURROGATE(ch)); ++i; deletedCharsArray.AppendElement(true); // not exactly deleted, but the // trailing surrogate is skipped ++extraChars; } while (extraChars-- > 0) { mergeNeeded = true; charsToMergeArray.AppendElement(true); styleArray.AppendElement(styleContext); canBreakBeforeArray.AppendElement(false); } } } PRUint32 flags; gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &flags, aRefContext); gfxFontGroup* fontGroup = aTextRun->GetFontGroup(); nsAutoPtr<nsTransformedTextRun> transformedChild; nsAutoPtr<gfxTextRun> cachedChild; gfxTextRun* child; if (mInnerTransformingTextRunFactory) { transformedChild = mInnerTransformingTextRunFactory->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), &innerParams, fontGroup, flags, styleArray.Elements(), false); child = transformedChild.get(); } else { cachedChild = fontGroup->MakeTextRun( convertedString.BeginReading(), convertedString.Length(), &innerParams, flags); child = cachedChild.get(); } if (!child) return; // Copy potential linebreaks into child so they're preserved // (and also child will be shaped appropriately) NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(), "Dropped characters or break-before values somewhere!"); child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), canBreakBeforeArray.Elements(), aRefContext); if (transformedChild) { transformedChild->FinishSettingProperties(aRefContext); } if (mergeNeeded) { // Now merge multiple characters into one multi-glyph character as required // and deal with skipping deleted accent chars NS_ASSERTION(charsToMergeArray.Length() == child->GetLength(), "source length mismatch"); NS_ASSERTION(deletedCharsArray.Length() == aTextRun->GetLength(), "destination length mismatch"); MergeCharactersInTextRun(aTextRun, child, charsToMergeArray.Elements(), deletedCharsArray.Elements()); } else { // No merging to do, so just copy; this produces a more optimized textrun. // We can't steal the data because the child may be cached and stealing // the data would break the cache. aTextRun->ResetGlyphRuns(); aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0); } }