Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/layout/xul/tree/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 20 kB image not shown  

Quelle  nsTreeSelection.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/Element.h"
#include "nsCOMPtr.h"
#include "nsTreeSelection.h"
#include "XULTreeElement.h"
#include "nsITreeView.h"
#include "nsString.h"
#include "nsIContent.h"
#include "nsNameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsComponentManagerUtils.h"
#include "nsTreeColumns.h"

using namespace mozilla;
using dom::XULTreeElement;

// A helper class for managing our ranges of selection.
struct nsTreeRange {
  nsTreeSelection* mSelection;

  nsTreeRange* mPrev;
  nsTreeRange* mNext;

  int32_t mMin;
  int32_t mMax;

  nsTreeRange(nsTreeSelection* aSel, int32_t aSingleVal)
      : mSelection(aSel),
        mPrev(nullptr),
        mNext(nullptr),
        mMin(aSingleVal),
        mMax(aSingleVal) {}
  nsTreeRange(nsTreeSelection* aSel, int32_t aMin, int32_t aMax)
      : mSelection(aSel),
        mPrev(nullptr),
        mNext(nullptr),
        mMin(aMin),
        mMax(aMax) {}

  ~nsTreeRange() { delete mNext; }

  void Connect(nsTreeRange* aPrev = nullptr, nsTreeRange* aNext = nullptr) {
    if (aPrev) {
      aPrev->mNext = this;
    } else {
      mSelection->mFirstRange = this;
    }

    if (aNext) {
      aNext->mPrev = this;
    }

    mPrev = aPrev;
    mNext = aNext;
  }

  nsresult RemoveRange(int32_t aStart, int32_t aEnd) {
    // This should so be a loop... sigh...
    // We start past the range to remove, so no more to remove
    if (aEnd < mMin) {
      return NS_OK;
    }
    // We are the last range to be affected
    if (aEnd < mMax) {
      if (aStart <= mMin) {
        // Just chop the start of the range off
        mMin = aEnd + 1;
      } else {
        // We need to split the range
        nsTreeRange* range = new nsTreeRange(mSelection, aEnd + 1, mMax);
        if (!range) {
          return NS_ERROR_OUT_OF_MEMORY;
        }

        mMax = aStart - 1;
        range->Connect(this, mNext);
      }
      return NS_OK;
    }
    nsTreeRange* next = mNext;
    if (aStart <= mMin) {
      // The remove includes us, remove ourselves from the list
      if (mPrev) {
        mPrev->mNext = next;
      } else {
        mSelection->mFirstRange = next;
      }

      if (next) {
        next->mPrev = mPrev;
      }
      mPrev = mNext = nullptr;
      delete this;
    } else if (aStart <= mMax) {
      // Just chop the end of the range off
      mMax = aStart - 1;
    }
    return next ? next->RemoveRange(aStart, aEnd) : NS_OK;
  }

  nsresult Remove(int32_t aIndex) {
    if (aIndex >= mMin && aIndex <= mMax) {
      // We have found the range that contains us.
      if (mMin == mMax) {
        // Delete the whole range.
        if (mPrev) {
          mPrev->mNext = mNext;
        }
        if (mNext) {
          mNext->mPrev = mPrev;
        }
        nsTreeRange* first = mSelection->mFirstRange;
        if (first == this) {
          mSelection->mFirstRange = mNext;
        }
        mNext = mPrev = nullptr;
        delete this;
      } else if (aIndex == mMin) {
        mMin++;
      } else if (aIndex == mMax) {
        mMax--;
      } else {
        // We have to break this range.
        nsTreeRange* newRange = new nsTreeRange(mSelection, aIndex + 1, mMax);
        if (!newRange) {
          return NS_ERROR_OUT_OF_MEMORY;
        }

        newRange->Connect(this, mNext);
        mMax = aIndex - 1;
      }
    } else if (mNext) {
      return mNext->Remove(aIndex);
    }

    return NS_OK;
  }

  nsresult Add(int32_t aIndex) {
    if (aIndex < mMin) {
      // We have found a spot to insert.
      if (aIndex + 1 == mMin) {
        mMin = aIndex;
      } else if (mPrev && mPrev->mMax + 1 == aIndex) {
        mPrev->mMax = aIndex;
      } else {
        // We have to create a new range.
        nsTreeRange* newRange = new nsTreeRange(mSelection, aIndex);
        if (!newRange) {
          return NS_ERROR_OUT_OF_MEMORY;
        }

        newRange->Connect(mPrev, this);
      }
    } else if (mNext) {
      mNext->Add(aIndex);
    } else {
      // Insert on to the end.
      if (mMax + 1 == aIndex) {
        mMax = aIndex;
      } else {
        // We have to create a new range.
        nsTreeRange* newRange = new nsTreeRange(mSelection, aIndex);
        if (!newRange) {
          return NS_ERROR_OUT_OF_MEMORY;
        }

        newRange->Connect(this, nullptr);
      }
    }
    return NS_OK;
  }

  bool Contains(int32_t aIndex) {
    if (aIndex >= mMin && aIndex <= mMax) {
      return true;
    }

    if (mNext) {
      return mNext->Contains(aIndex);
    }

    return false;
  }

  int32_t Count() {
    int32_t total = mMax - mMin + 1;
    if (mNext) {
      total += mNext->Count();
    }
    return total;
  }

  static void CollectRanges(nsTreeRange* aRange, nsTArray<int32_t>& aRanges) {
    nsTreeRange* cur = aRange;
    while (cur) {
      aRanges.AppendElement(cur->mMin);
      aRanges.AppendElement(cur->mMax);
      cur = cur->mNext;
    }
  }

  static void InvalidateRanges(XULTreeElement* aTree,
                               nsTArray<int32_t>& aRanges) {
    if (aTree) {
      RefPtr<nsXULElement> tree = aTree;
      for (uint32_t i = 0; i < aRanges.Length(); i += 2) {
        aTree->InvalidateRange(aRanges[i], aRanges[i + 1]);
      }
    }
  }

  void Invalidate() {
    nsTArray<int32_t> ranges;
    CollectRanges(this, ranges);
    InvalidateRanges(mSelection->mTree, ranges);
  }

  void RemoveAllBut(int32_t aIndex) {
    if (aIndex >= mMin && aIndex <= mMax) {
      // Invalidate everything in this list.
      nsTArray<int32_t> ranges;
      CollectRanges(mSelection->mFirstRange, ranges);

      mMin = aIndex;
      mMax = aIndex;

      nsTreeRange* first = mSelection->mFirstRange;
      if (mPrev) {
        mPrev->mNext = mNext;
      }
      if (mNext) {
        mNext->mPrev = mPrev;
      }
      mNext = mPrev = nullptr;

      if (first != this) {
        delete mSelection->mFirstRange;
        mSelection->mFirstRange = this;
      }
      InvalidateRanges(mSelection->mTree, ranges);
    } else if (mNext) {
      mNext->RemoveAllBut(aIndex);
    }
  }

  void Insert(nsTreeRange* aRange) {
    if (mMin >= aRange->mMax) {
      aRange->Connect(mPrev, this);
    } else if (mNext) {
      mNext->Insert(aRange);
    } else {
      aRange->Connect(this, nullptr);
    }
  }
};

nsTreeSelection::nsTreeSelection(XULTreeElement* aTree)
    : mTree(aTree),
      mSuppressed(false),
      mCurrentIndex(-1),
      mShiftSelectPivot(-1),
      mFirstRange(nullptr) {}

nsTreeSelection::~nsTreeSelection() {
  delete mFirstRange;
  if (mSelectTimer) {
    mSelectTimer->Cancel();
  }
}

NS_IMPL_CYCLE_COLLECTION(nsTreeSelection, mTree)

NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeSelection)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeSelection)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeSelection)
  NS_INTERFACE_MAP_ENTRY(nsITreeSelection)
  NS_INTERFACE_MAP_ENTRY(nsINativeTreeSelection)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMETHODIMP nsTreeSelection::GetTree(XULTreeElement** aTree) {
  NS_IF_ADDREF(*aTree = mTree);
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::SetTree(XULTreeElement* aTree) {
  if (mSelectTimer) {
    mSelectTimer->Cancel();
    mSelectTimer = nullptr;
  }

  mTree = aTree;
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::GetSingle(bool* aSingle) {
  if (!mTree) {
    return NS_ERROR_NULL_POINTER;
  }

  *aSingle = mTree->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype,
                                u"single"_ns, eCaseMatters);

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::IsSelected(int32_t aIndex, bool* aResult) {
  if (mFirstRange) {
    *aResult = mFirstRange->Contains(aIndex);
  } else {
    *aResult = false;
  }
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::TimedSelect(int32_t aIndex, int32_t aMsec) {
  bool suppressSelect = mSuppressed;

  if (aMsec != -1) {
    mSuppressed = true;
  }

  nsresult rv = Select(aIndex);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (aMsec != -1) {
    mSuppressed = suppressSelect;
    if (!mSuppressed) {
      if (mSelectTimer) {
        mSelectTimer->Cancel();
      }

      if (!mTree) {
        return NS_ERROR_UNEXPECTED;
      }
      nsIEventTarget* target = GetMainThreadSerialEventTarget();
      NS_NewTimerWithFuncCallback(getter_AddRefs(mSelectTimer), SelectCallback,
                                  this, aMsec, nsITimer::TYPE_ONE_SHOT,
                                  "nsTreeSelection::SelectCallback", target);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::Select(int32_t aIndex) {
  mShiftSelectPivot = -1;

  nsresult rv = SetCurrentIndex(aIndex);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (mFirstRange) {
    bool alreadySelected = mFirstRange->Contains(aIndex);

    if (alreadySelected) {
      int32_t count = mFirstRange->Count();
      if (count > 1) {
        // We need to deselect everything but our item.
        mFirstRange->RemoveAllBut(aIndex);
        FireOnSelectHandler();
      }
      return NS_OK;
    } else {
      // Clear out our selection.
      mFirstRange->Invalidate();
      delete mFirstRange;
    }
  }

  // Create our new selection.
  mFirstRange = new nsTreeRange(this, aIndex);
  if (!mFirstRange) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  mFirstRange->Invalidate();

  // Fire the select event
  FireOnSelectHandler();
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::ToggleSelect(int32_t aIndex) {
  // There are six cases that can occur on a ToggleSelect with our
  // range code.
  // (1) A new range should be made for a selection.
  // (2) A single range is removed from the selection.
  // (3) The item is added to an existing range.
  // (4) The item is removed from an existing range.
  // (5) The addition of the item causes two ranges to be merged.
  // (6) The removal of the item causes two ranges to be split.
  mShiftSelectPivot = -1;
  nsresult rv = SetCurrentIndex(aIndex);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (!mFirstRange) {
    Select(aIndex);
  } else {
    if (!mFirstRange->Contains(aIndex)) {
      bool single;
      rv = GetSingle(&single);
      if (NS_SUCCEEDED(rv) && !single) {
        rv = mFirstRange->Add(aIndex);
      }
    } else {
      rv = mFirstRange->Remove(aIndex);
    }
    if (NS_SUCCEEDED(rv)) {
      if (mTree) {
        mTree->InvalidateRow(aIndex);
      }

      FireOnSelectHandler();
    }
  }

  return rv;
}

NS_IMETHODIMP nsTreeSelection::RangedSelect(int32_t aStartIndex,
                                            int32_t aEndIndex, bool aAugment) {
  bool single;
  nsresult rv = GetSingle(&single);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if ((mFirstRange || (aStartIndex != aEndIndex)) && single) {
    return NS_OK;
  }

  if (!aAugment) {
    // Clear our selection.
    if (mFirstRange) {
      mFirstRange->Invalidate();
      delete mFirstRange;
      mFirstRange = nullptr;
    }
  }

  if (aStartIndex == -1) {
    if (mShiftSelectPivot != -1) {
      aStartIndex = mShiftSelectPivot;
    } else if (mCurrentIndex != -1) {
      aStartIndex = mCurrentIndex;
    } else {
      aStartIndex = aEndIndex;
    }
  }

  mShiftSelectPivot = aStartIndex;
  rv = SetCurrentIndex(aEndIndex);
  if (NS_FAILED(rv)) {
    return rv;
  }

  int32_t start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex;
  int32_t end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex;

  if (aAugment && mFirstRange) {
    // We need to remove all the items within our selected range from the
    // selection, and then we insert our new range into the list.
    nsresult rv = mFirstRange->RemoveRange(start, end);
    if (NS_FAILED(rv)) {
      return rv;
    }
  }

  nsTreeRange* range = new nsTreeRange(this, start, end);
  if (!range) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  range->Invalidate();

  if (aAugment && mFirstRange) {
    mFirstRange->Insert(range);
  } else {
    mFirstRange = range;
  }

  FireOnSelectHandler();

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::ClearRange(int32_t aStartIndex,
                                          int32_t aEndIndex) {
  nsresult rv = SetCurrentIndex(aEndIndex);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (mFirstRange) {
    int32_t start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex;
    int32_t end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex;

    mFirstRange->RemoveRange(start, end);

    if (mTree) {
      mTree->InvalidateRange(start, end);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::ClearSelection() {
  if (mFirstRange) {
    mFirstRange->Invalidate();
    delete mFirstRange;
    mFirstRange = nullptr;
  }
  mShiftSelectPivot = -1;

  FireOnSelectHandler();

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::SelectAll() {
  if (!mTree) {
    return NS_OK;
  }

  nsCOMPtr<nsITreeView> view = mTree->GetView();
  if (!view) {
    return NS_OK;
  }

  int32_t rowCount;
  view->GetRowCount(&rowCount);
  bool single;
  nsresult rv = GetSingle(&single);
  if (NS_FAILED(rv)) {
    return rv;
  }

  if (rowCount == 0 || (rowCount > 1 && single)) {
    return NS_OK;
  }

  mShiftSelectPivot = -1;

  // Invalidate not necessary when clearing selection, since
  // we're going to invalidate the world on the SelectAll.
  delete mFirstRange;

  mFirstRange = new nsTreeRange(this, 0, rowCount - 1);
  mFirstRange->Invalidate();

  FireOnSelectHandler();

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::GetRangeCount(int32_t* aResult) {
  int32_t count = 0;
  nsTreeRange* curr = mFirstRange;
  while (curr) {
    count++;
    curr = curr->mNext;
  }

  *aResult = count;
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::GetRangeAt(int32_t aIndex, int32_t* aMin,
                                          int32_t* aMax) {
  *aMin = *aMax = -1;
  int32_t i = -1;
  nsTreeRange* curr = mFirstRange;
  while (curr) {
    i++;
    if (i == aIndex) {
      *aMin = curr->mMin;
      *aMax = curr->mMax;
      break;
    }
    curr = curr->mNext;
  }

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::GetCount(int32_t* count) {
  if (mFirstRange) {
    *count = mFirstRange->Count();
  } else {  // No range available, so there's no selected row.
    *count = 0;
  }

  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::GetSelectEventsSuppressed(
    bool* aSelectEventsSuppressed) {
  *aSelectEventsSuppressed = mSuppressed;
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::SetSelectEventsSuppressed(
    bool aSelectEventsSuppressed) {
  mSuppressed = aSelectEventsSuppressed;
  if (!mSuppressed) {
    FireOnSelectHandler();
  }
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::GetCurrentIndex(int32_t* aCurrentIndex) {
  *aCurrentIndex = mCurrentIndex;
  return NS_OK;
}

NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(int32_t aIndex) {
  if (!mTree) {
    return NS_ERROR_UNEXPECTED;
  }
  if (mCurrentIndex == aIndex) {
    return NS_OK;
  }
  if (mCurrentIndex != -1 && mTree) {
    mTree->InvalidateRow(mCurrentIndex);
  }

  mCurrentIndex = aIndex;
  if (!mTree) {
    return NS_OK;
  }

  if (aIndex != -1) {
    mTree->InvalidateRow(aIndex);
  }

  // Fire DOMMenuItemActive or DOMMenuItemInactive event for tree.
  NS_ENSURE_STATE(mTree);

  constexpr auto DOMMenuItemActive = u"DOMMenuItemActive"_ns;
  constexpr auto DOMMenuItemInactive = u"DOMMenuItemInactive"_ns;

  RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
      mTree, (aIndex != -1 ? DOMMenuItemActive : DOMMenuItemInactive),
      CanBubble::eYes, ChromeOnlyDispatch::eNo);
  return asyncDispatcher->PostDOMEvent();
}

#define ADD_NEW_RANGE(macro_range, macro_selection, macro_start, macro_end) \
  {                                                                         \
    int32_t start = macro_start;                                            \
    int32_t end = macro_end;                                                \
    if (start > end) {                                                      \
      end = start;                                                          \
    }                                                                       \
    nsTreeRange* macro_new_range =                                          \
        new nsTreeRange(macro_selection, start, end);                       \
    if (macro_range)                                                        \
      macro_range->Insert(macro_new_range);                                 \
    else                                                                    \
      macro_range = macro_new_range;                                        \
  }

NS_IMETHODIMP
nsTreeSelection::AdjustSelection(int32_t aIndex, int32_t aCount) {
  NS_ASSERTION(aCount != 0, "adjusting by zero");
  if (!aCount) {
    return NS_OK;
  }

  // adjust mShiftSelectPivot, if necessary
  if ((mShiftSelectPivot != 1) && (aIndex <= mShiftSelectPivot)) {
    // if we are deleting and the delete includes the shift select pivot, reset
    // it
    if (aCount < 0 && (mShiftSelectPivot <= (aIndex - aCount - 1))) {
      mShiftSelectPivot = -1;
    } else {
      mShiftSelectPivot += aCount;
    }
  }

  // adjust mCurrentIndex, if necessary
  if ((mCurrentIndex != -1) && (aIndex <= mCurrentIndex)) {
    // if we are deleting and the delete includes the current index, reset it
    if (aCount < 0 && (mCurrentIndex <= (aIndex - aCount - 1))) {
      mCurrentIndex = -1;
    } else {
      mCurrentIndex += aCount;
    }
  }

  // no selection, so nothing to do.
  if (!mFirstRange) {
    return NS_OK;
  }

  bool selChanged = false;
  nsTreeRange* oldFirstRange = mFirstRange;
  nsTreeRange* curr = mFirstRange;
  mFirstRange = nullptr;
  while (curr) {
    if (aCount > 0) {
      // inserting
      if (aIndex > curr->mMax) {
        // adjustment happens after the range, so no change
        ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax);
      } else if (aIndex <= curr->mMin) {
        // adjustment happens before the start of the range, so shift down
        ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount,
                      curr->mMax + aCount);
        selChanged = true;
      } else {
        // adjustment happen inside the range.
        // break apart the range and create two ranges
        ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1);
        ADD_NEW_RANGE(mFirstRange, this, aIndex + aCount, curr->mMax + aCount);
        selChanged = true;
      }
    } else {
      // deleting
      if (aIndex > curr->mMax) {
        // adjustment happens after the range, so no change
        ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax);
      } else {
        // remember, aCount is negative
        selChanged = true;
        int32_t lastIndexOfAdjustment = aIndex - aCount - 1;
        if (aIndex <= curr->mMin) {
          if (lastIndexOfAdjustment < curr->mMin) {
            // adjustment happens before the start of the range, so shift up
            ADD_NEW_RANGE(mFirstRange, this, curr->mMin + aCount,
                          curr->mMax + aCount);
          } else if (lastIndexOfAdjustment >= curr->mMax) {
            // adjustment contains the range.  remove the range by not adding it
            // to the newRange
          } else {
            // adjustment starts before the range, and ends in the middle of it,
            // so trim the range
            ADD_NEW_RANGE(mFirstRange, this, aIndex, curr->mMax + aCount)
          }
        } else if (lastIndexOfAdjustment >= curr->mMax) {
          // adjustment starts in the middle of the current range, and contains
          // the end of the range, so trim the range
          ADD_NEW_RANGE(mFirstRange, this, curr->mMin, aIndex - 1)
        } else {
          // range contains the adjustment, so shorten the range
          ADD_NEW_RANGE(mFirstRange, this, curr->mMin, curr->mMax + aCount)
        }
      }
    }
    curr = curr->mNext;
  }

  delete oldFirstRange;

  // Fire the select event
  if (selChanged) {
    FireOnSelectHandler();
  }

  return NS_OK;
}

NS_IMETHODIMP
nsTreeSelection::InvalidateSelection() {
  if (mFirstRange) {
    mFirstRange->Invalidate();
  }
  return NS_OK;
}

NS_IMETHODIMP
nsTreeSelection::GetShiftSelectPivot(int32_t* aIndex) {
  *aIndex = mShiftSelectPivot;
  return NS_OK;
}

nsresult nsTreeSelection::FireOnSelectHandler() {
  if (mSuppressed || !mTree) {
    return NS_OK;
  }

  AsyncEventDispatcher::RunDOMEventWhenSafe(
      *mTree, u"select"_ns, CanBubble::eYes, ChromeOnlyDispatch::eNo);
  return NS_OK;
}

void nsTreeSelection::SelectCallback(nsITimer* aTimer, void* aClosure) {
  RefPtr<nsTreeSelection> self = static_cast<nsTreeSelection*>(aClosure);
  if (self) {
    self->FireOnSelectHandler();
    aTimer->Cancel();
    self->mSelectTimer = nullptr;
  }
}

///////////////////////////////////////////////////////////////////////////////////

nsresult NS_NewTreeSelection(XULTreeElement* aTree,
                             nsITreeSelection** aResult) {
  *aResult = new nsTreeSelection(aTree);
  if (!*aResult) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  NS_ADDREF(*aResult);
  return NS_OK;
}

Messung V0.5
C=94 H=96 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.