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
}
Beispiel #6
0
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;
}
Beispiel #11
0
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)));
}
Beispiel #13
0
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
}
Beispiel #15
0
void
nsPresArena::FreeBySize(size_t aSize, void* aPtr)
{
    mState->Free(PRUint32(aSize) |
                 PRUint32(nsQueryFrame::NON_FRAME_MARKER), aPtr);
}
Beispiel #16
0
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);
}
Beispiel #18
0
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;
}
Beispiel #26
0
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);
}
Beispiel #28
0
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);
  }
}