text:
"""Fake LDAP server for test harness.

This class does very little error checking, and knows nothing about ldap
class definitions.  It implements the minimum emulation of the python ldap
library to work with nova.

"""

import re
import shelve

import ldap
import six
from six import moves

from keystone.common.ldap import core
from keystone import exception
from keystone.openstack.common import log

SCOPE_NAMES = {
    ldap.SCOPE_BASE: 'SCOPE_BASE',
    ldap.SCOPE_ONELEVEL: 'SCOPE_ONELEVEL',
    ldap.SCOPE_SUBTREE: 'SCOPE_SUBTREE',
}

# http://msdn.microsoft.com\
#     /en-us/library/windows/desktop/aa366991(v=vs.85).aspx
CONTROL_TREEDELETE = '1.2.840.113556.1.4.805'

LOG = log.getLogger(__name__)

def _internal_attr(attr_name, value_or_values):
    def normalize_value(value):
        return core.utf8_decode(value)

    def normalize_dn(dn):
        # Capitalize the attribute names as an LDAP server might.

        # NOTE(blk-u): Special case for this tested value, used with
        # test_user_id_comma. The call to str2dn here isn't always correct
        # here, because `dn` is escaped for an LDAP filter. str2dn() normally
        # works only because there's no special characters in `dn`.
        if dn == 'cn=Doe\\5c, John,ou=Users,cn=example,cn=com':
            return 'CN=Doe\\, John,OU=Users,CN=example,CN=com'

        # NOTE(blk-u): Another special case for this tested value. When a
        # roleOccupant has an escaped comma, it gets converted to \2C.
        if dn == 'cn=Doe\\, John,ou=Users,cn=example,cn=com':
            return 'CN=Doe\\2C John,OU=Users,CN=example,CN=com'

        dn = ldap.dn.str2dn(core.utf8_encode(dn))
        norm = []
        for part in dn:
            name, val, i = part[0]
            name = core.utf8_decode(name)
            name = name.upper()
            name = core.utf8_encode(name)
            norm.append([(name, val, i)])
        return core.utf8_decode(ldap.dn.dn2str(norm))

    if attr_name in ('member', 'roleOccupant'):
        attr_fn = normalize_dn
    else:
        attr_fn = normalize_value

    if isinstance(value_or_values, list):
        return [attr_fn(x) for x in value_or_values]
    return [attr_fn(value_or_values)]

def _match_query(query, attrs):
    """Match an ldap query to an attribute dictionary.

    The characters &, |, and ! are supported in the query. No syntax checking
    is performed, so malformed queries will not work correctly.
    """
    # cut off the parentheses
    inner = query[1:-1]
    if inner.startswith(('&', '|')):
        # cut off the & or |
        groups = _paren_groups(inner[1:])
        return all(_match_query(group, attrs) for group in groups)
    if inner.startswith('!'):
        # cut off the ! and the nested parentheses
        return not _match_query(query[2:-1], attrs)

    (k, _sep, v) = inner.partition('=')
    return _match(k, v, attrs)

def _paren_groups(source):
    """Split a string into parenthesized groups."""
    count = 0
    start = 0
    result = []
    for pos in moves.range(len(source)):
        if source[pos] == '(':
            if count == 0:
                start = pos
            count += 1
        if source[pos] == ')':
            count -= 1
            if count == 0:
                result.append(source[start:pos + 1])
    return result

def _match(key, value, attrs):
    """Match a given key and value against an attribute list."""
    if key not in attrs:
        return False
    # This is a wild card search. Implemented as all or nothing for now.
    if value == '*':
        return True
    if key == 'serviceId':
        # for serviceId, the backend is returning a list of numbers
        # make sure we convert them to strings first before comparing
        # them
        str_sids = [six.text_type(x) for x in attrs[key]]
        return six.text_type(value) in str_sids
    if key != 'objectclass':
        check_value = _internal_attr(key, value)[0]
        norm_values = list(_internal_attr(key, x)[0] for x in attrs[key])
        return check_value in norm_values
    # it is an objectclass check, so check subclasses
    values = _subs(value)
    for v in values:
        if v in attrs[key]:
            return True
    return False

def _subs(value):
    """Returns a list of subclass strings.

    The strings represent the ldap objectclass plus any subclasses that
    inherit from it. Fakeldap doesn't know about the ldap object structure,
    so subclasses need to be defined manually in the dictionary below.

    """
    subs = {'groupOfNames': ['keystoneTenant',
                             'keystoneRole',
                             'keystoneTenantRole']}
    if value in subs:
        return [value] + subs[value]
    return [value]

server_fail = False

class FakeShelve(dict):

    def sync(self):
        pass

FakeShelves = {}

class FakeLdap(core.LDAPHandler):
    '''Emulate the python-ldap API.

    The python-ldap API requires all strings to be UTF-8 encoded. This
    is assured by the caller of this interface
    (i.e. KeystoneLDAPHandler).

    However, internally this emulation MUST process and store strings
    in a canonical form which permits operations on
    characters. Encoded strings do not provide the ability to operate
    on characters. Therefore this emulation accepts UTF-8 encoded
    strings, decodes them to unicode for operations internal to this
    emulation, and encodes them back to UTF-8 when returning values
    from the emulation.
    '''

    __prefix = 'ldap:'

    def __init__(self, conn=None):
        super(FakeLdap, self).__init__(conn=conn)
        self._ldap_options = {ldap.OPT_DEREF: ldap.DEREF_NEVER}

    def connect(self, url, page_size=0, alias_dereferencing=None,
                use_tls=False, tls_cacertfile=None, tls_cacertdir=None,
                tls_req_cert='demand', chase_referrals=None, debug_level=None):
        if url.startswith('fake://memory'):
            if url not in FakeShelves:
                FakeShelves[url] = FakeShelve()
            self.db = FakeShelves[url]
        else:
            self.db = shelve.open(url[7:])

        using_ldaps = url.lower().startswith("ldaps")

        if use_tls and using_ldaps:
            raise AssertionError('Invalid TLS / LDAPS combination')

        if use_tls:
            if tls_cacertfile:
                ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile)
            elif tls_cacertdir:
                ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, tls_cacertdir)
            if tls_req_cert in core.LDAP_TLS_CERTS.values():
                ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_cert)
            else:
                raise ValueError("invalid TLS_REQUIRE_CERT tls_req_cert=%s",
                                 tls_req_cert)

        if alias_dereferencing is not None:
            self.set_option(ldap.OPT_DEREF, alias_dereferencing)
        self.page_size = page_size

    def dn(self, dn):
        return core.utf8_decode(dn)

    def key(self, dn):
        return '%s%s' % (self.__prefix, self.dn(dn))

    def simple_bind_s(self, who='', cred='',
                      serverctrls=None, clientctrls=None):
        """This method is ignored, but provided for compatibility."""
        if server_fail:
            raise ldap.SERVER_DOWN
        if who == 'cn=Admin' and cred == 'password':
            return

        try:
            attrs = self.db[self.key(who)]
        except KeyError:
            LOG.debug('bind fail: who=%s not found', core.utf8_decode(who))
            raise ldap.NO_SUCH_OBJECT

        db_password = None
        try:
            db_password = attrs['userPassword'][0]
        except (KeyError, IndexError):
            LOG.debug('bind fail: password for who=%s not found',
                      core.utf8_decode(who))
            raise ldap.INAPPROPRIATE_AUTH

        if cred != db_password:
            LOG.debug('bind fail: password for who=%s does not match',
                      core.utf8_decode(who))
            raise ldap.INVALID_CREDENTIALS

    def unbind_s(self):
        """This method is ignored, but provided for compatibility."""
        if server_fail:
            raise ldap.SERVER_DOWN

    def add_s(self, dn, modlist):
        """Add an object with the specified attributes at dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        # The LDAP API raises a TypeError if attr name is None.
        for k, dummy_v in modlist:
            if k is None:
                raise TypeError('must be string, not None. modlist=%s' %
                                modlist)

        key = self.key(dn)
        LOG.debug('add item: dn=%(dn)s, attrs=%(attrs)s', {
            'dn': dn, 'attrs': modlist})
        if key in self.db:
            LOG.debug('add item failed: dn=%s is already in store.',
                      core.utf8_decode(dn))
            raise ldap.ALREADY_EXISTS(dn)

        self.db[key] = dict([(k, _internal_attr(k, v))
                             for k, v in modlist])
        self.db.sync()

    def delete_s(self, dn):
        """Remove the ldap object at specified dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        key = self.key(dn)
        LOG.debug('delete item: dn=%s', dn)
        try:
            del self.db[key]
        except KeyError:
            LOG.debug('delete item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT
        self.db.sync()

    def delete_ext_s(self, dn, serverctrls, clientctrls=None):
        """Remove the ldap object at specified dn."""
        if server_fail:
            raise ldap.SERVER_DOWN

        try:
            if CONTROL_TREEDELETE in [c.controlType for c in serverctrls]:
                LOG.debug('FakeLdap subtree_delete item: dn=%s',
                          core.utf8_decode(dn))
                children = [k for k, v in six.iteritems(self.db)
                            if re.match('%s.*,%s' % (
                                        re.escape(self.__prefix),
                                        re.escape(self.dn(dn))), k)]
                for c in children:
                    del self.db[c]

            key = self.key(dn)
            LOG.debug('FakeLdap delete item: dn=%s', dn)
            del self.db[key]
        except KeyError:
            LOG.debug('delete item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT
        self.db.sync()

    def modify_s(self, dn, modlist):
        """Modify the object at dn using the attribute list.

        :param dn: an LDAP DN
        :param modlist: a list of tuples in the following form:
                      ([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
        """
        if server_fail:
            raise ldap.SERVER_DOWN

        key = self.key(dn)
        LOG.debug('modify item: dn=%(dn)s attrs=%(attrs)s', {
            'dn': dn, 'attrs': modlist})
        try:
            entry = self.db[key]
        except KeyError:
            LOG.debug('modify item failed: dn=%s not found.',
                      core.utf8_decode(dn))
            raise ldap.NO_SUCH_OBJECT

        for cmd, k, v in modlist:
            values = entry.setdefault(k, [])
            if cmd == ldap.MOD_ADD:
                v = _internal_attr(k, v)
                for x in v:
                    if x in values:
                        raise ldap.TYPE_OR_VALUE_EXISTS
                values += v
            elif cmd == ldap.MOD_REPLACE:
                values[:] = _internal_attr(k, v)
            elif cmd == ldap.MOD_DELETE:
                if v is None:
                    if not values:
                        LOG.debug('modify item failed: '
                                  'item has no attribute "%s" to delete', k)
                        raise ldap.NO_SUCH_ATTRIBUTE
                    values[:] = []
                else:
                    for val in _internal_attr(k, v):
                        try:
                            values.remove(val)
                        except ValueError:
                            LOG.debug('modify item failed: '
                                      'item has no attribute "%(k)s" with '
                                      'value "%(v)s" to delete', {
                                          'k': k, 'v': val})
                            raise ldap.NO_SUCH_ATTRIBUTE
            else:
                LOG.debug('modify item failed: unknown command %s', cmd)
                raise NotImplementedError('modify_s action %s not'
                                          ' implemented' % cmd)
        self.db[key] = entry
        self.db.sync()

    def search_s(self, base, scope,
                 filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
        """Search for all matching objects under base using the query.

        Args:
        base -- dn to search under
        scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
        filterstr -- filter objects by
        attrlist -- attrs to return. Returns all attrs if not specified

        """
        if server_fail:
            raise ldap.SERVER_DOWN

        if scope == ldap.SCOPE_BASE:
            try:
                item_dict = self.db[self.key(base)]
            except KeyError:
                LOG.debug('search fail: dn not found for SCOPE_BASE')
                raise ldap.NO_SUCH_OBJECT
            results = [(base, item_dict)]
        elif scope == ldap.SCOPE_SUBTREE:
            results = [(k[len(self.__prefix):], v)
                       for k, v in six.iteritems(self.db)
                       if re.match('%s.*,%s' % (re.escape(self.__prefix),
                                                re.escape(self.dn(base))), k)]
        elif scope == ldap.SCOPE_ONELEVEL:

            def get_entries():
                base_dn = ldap.dn.str2dn(core.utf8_encode(base))
                base_len = len(base_dn)

                for k, v in six.iteritems(self.db):
                    if not k.startswith(self.__prefix):
                        continue
                    k_dn_str = k[len(self.__prefix):]
                    k_dn = ldap.dn.str2dn(core.utf8_encode(k_dn_str))
                    if len(k_dn) != base_len + 1:
                        continue
                    if k_dn[-base_len:] != base_dn:
                        continue
                    yield (k_dn_str, v)

            results = list(get_entries())

        else:
            LOG.debug('search fail: unknown scope %s', scope)
            raise NotImplementedError('Search scope %s not implemented.'
                                      % scope)

        objects = []
        for dn, attrs in results:
            # filter the objects by filterstr
            id_attr, id_val, _ = ldap.dn.str2dn(core.utf8_encode(dn))[0][0]
            id_attr = core.utf8_decode(id_attr)
            id_val = core.utf8_decode(id_val)
            match_attrs = attrs.copy()
            match_attrs[id_attr] = [id_val]
            if not filterstr or _match_query(filterstr, match_attrs):
                # filter the attributes by attrlist
                attrs = dict([(k, v) for k, v in six.iteritems(attrs)
                              if not attrlist or k in attrlist])
                objects.append((dn, attrs))

        return objects

    def set_option(self, option, invalue):
        self._ldap_options[option] = invalue

    def get_option(self, option):
        value = self._ldap_options.get(option, None)
        return value

    def search_ext(self, base, scope,
                   filterstr='(objectClass=*)', attrlist=None, attrsonly=0,
                   serverctrls=None, clientctrls=None,
                   timeout=-1, sizelimit=0):
        raise exception.NotImplemented()

    def result3(self, msgid=ldap.RES_ANY, all=1, timeout=None,
                resp_ctrl_classes=None):
        raise exception.NotImplemented()


text:
//
//  SSJSONModelClassProperty.h
//
//  @version 1.2
//  @author Marin Todorov (http://www.underplot.com) and contributors
//

// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
// This code is distributed under the terms and conditions of the MIT license.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import <Foundation/Foundation.h>

enum kCustomizationTypes {
    kNotInspected = 0,
    kCustom,
    kNo
};

typedef enum kCustomizationTypes PropertyGetterType;

/**
 * **You do not need to instantiate this class yourself.** This class is used internally by SSJSONModel
 * to inspect the declared properties of your model class.
 *
 * Class to contain the information, representing a class property
 * It features the property's name, type, whether it's a required property,
 * and (optionally) the class protocol
 */
@interface SSJSONModelClassProperty : NSObject

// deprecated
@property (assign, nonatomic) BOOL isIndex DEPRECATED_ATTRIBUTE;

/** The name of the declared property (not the ivar name) */
@property (copy, nonatomic) NSString *name;

/** A property class type  */
@property (assign, nonatomic) Class type;

/** Struct name if a struct */
@property (strong, nonatomic) NSString *structName;

/** The name of the protocol the property conforms to (or nil) */
@property (copy, nonatomic) NSString *protocol;

/** If YES, it can be missing in the input data, and the input would be still valid */
@property (assign, nonatomic) BOOL isOptional;

/** If YES - don't call any transformers on this property's value */
@property (assign, nonatomic) BOOL isStandardJSONType;

/** If YES - create a mutable object for the value of the property */
@property (assign, nonatomic) BOOL isMutable;

/** The status of property getter introspection in a model */
@property (assign, nonatomic) PropertyGetterType getterType;

/** a custom getter for this property, found in the owning model */
@property (assign, nonatomic) SEL customGetter;

/** custom setters for this property, found in the owning model */
@property (strong, nonatomic) NSMutableDictionary *customSetters;

@end

redpajama_set_name: RedPajamaGithub


text:
import {
  AbortException,
  arrayByteLength,
  arraysToBytes,
  createPromiseCapability,
  getVerbosityLevel,
  info,
  InvalidPDFException,
  isString,
  MissingPDFException,
  PasswordException,
  setVerbosityLevel,
  stringToPDFString,
  UnexpectedResponseException,
  UnknownErrorException,
  UNSUPPORTED_FEATURES,
  VerbosityLevel,
  warn,
} from "../shared/util.js";
import { clearPrimitiveCaches, Dict, Ref } from "./primitives.js";
import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager.js";
import { incrementalUpdate } from "./writer.js";
import { isNodeJS } from "../shared/is_node.js";
import { MessageHandler } from "../shared/message_handler.js";
import { PDFWorkerStream } from "./worker_stream.js";
import { XRefParseException } from "./core_utils.js";

class WorkerTask {
  constructor(name) {
    this.name = name;
    this.terminated = false;
    this._capability = createPromiseCapability();
  }

  get finished() {
    return this._capability.promise;
  }

  finish() {
    this._capability.resolve();
  }

  terminate() {
    this.terminated = true;
  }

  ensureNotTerminated() {
    if (this.terminated) {
      throw new Error("Worker task was terminated");
    }
  }
}

class WorkerMessageHandler {
  static setup(handler, port) {
    let testMessageProcessed = false;
    handler.on("test", function wphSetupTest(data) {
      if (testMessageProcessed) {
        return; // we already processed 'test' message once
      }
      testMessageProcessed = true;

      // check if Uint8Array can be sent to worker
      if (!(data instanceof Uint8Array)) {
        handler.send("test", null);
        return;
      }
      // making sure postMessage transfers are working
      const supportTransfers = data[0] === 255;
      handler.postMessageTransfers = supportTransfers;

      handler.send("test", { supportTransfers });
    });

    handler.on("configure", function wphConfigure(data) {
      setVerbosityLevel(data.verbosity);
    });

    handler.on("GetDocRequest", function wphSetupDoc(data) {
      return WorkerMessageHandler.createDocumentHandler(data, port);
    });
  }

  static createDocumentHandler(docParams, port) {
    // This context is actually holds references on pdfManager and handler,
    // until the latter is destroyed.
    let pdfManager;
    let terminated = false;
    let cancelXHRs = null;
    const WorkerTasks = [];
    const verbosity = getVerbosityLevel();

    const apiVersion = docParams.apiVersion;
    const workerVersion =
      typeof PDFJSDev !== "undefined" && !PDFJSDev.test("TESTING")
        ? PDFJSDev.eval("BUNDLE_VERSION")
        : null;
    if (apiVersion !== workerVersion) {
      throw new Error(
        `The API version "${apiVersion}" does not match ` +
          `the Worker version "${workerVersion}".`
      );
    }

    if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
      // Fail early, and predictably, rather than having (some) fonts fail to
      // load/render with slightly cryptic error messages in environments where
      // the `Array.prototype` has been *incorrectly* extended.
      //
      // PLEASE NOTE: We do *not* want to slow down font parsing by adding
      //              `hasOwnProperty` checks all over the code-base.
      const enumerableProperties = [];
      for (const property in []) {
        enumerableProperties.push(property);
      }
      if (enumerableProperties.length) {
        throw new Error(
          "The `Array.prototype` contains unexpected enumerable properties: " +
            enumerableProperties.join(", ") +
            "; thus breaking e.g. `for...in` iteration of `Array`s."
        );
      }

      // Ensure that (primarily) Node.js users won't accidentally attempt to use
      // a non-translated/non-polyfilled build of the library, since that would
      // quickly fail anyway because of missing functionality.
      if (
        (typeof PDFJSDev === "undefined" || PDFJSDev.test("SKIP_BABEL")) &&
        typeof ReadableStream === "undefined"
      ) {
        throw new Error(
          "The browser/environment lacks native support for critical " +
            "functionality used by the PDF.js library (e.g. `ReadableStream`); " +
            "please use a `legacy`-build instead."
        );
      }
    }

    const docId = docParams.docId;
    const docBaseUrl = docParams.docBaseUrl;
    const workerHandlerName = docParams.docId + "_worker";
    let handler = new MessageHandler(workerHandlerName, docId, port);

    // Ensure that postMessage transfers are always correctly enabled/disabled,
    // to prevent "DataCloneError" in browsers without transfers support.
    handler.postMessageTransfers = docParams.postMessageTransfers;

    function ensureNotTerminated() {
      if (terminated) {
        throw new Error("Worker was terminated");
      }
    }

    function startWorkerTask(task) {
      WorkerTasks.push(task);
    }

    function finishWorkerTask(task) {
      task.finish();
      const i = WorkerTasks.indexOf(task);
      WorkerTasks.splice(i, 1);
    }

    async function loadDocument(recoveryMode) {
      await pdfManager.ensureDoc("checkHeader");
      await pdfManager.ensureDoc("parseStartXRef");
      await pdfManager.ensureDoc("parse", [recoveryMode]);

      if (!recoveryMode) {
        // Check that at least the first page can be successfully loaded,
        // since otherwise the XRef table is definitely not valid.
        await pdfManager.ensureDoc("checkFirstPage");
      }

      const isPureXfa = await pdfManager.ensureDoc("isPureXfa");
      if (isPureXfa) {
        const task = new WorkerTask("loadXfaFonts");
        startWorkerTask(task);
        await Promise.all([
          pdfManager
            .loadXfaFonts(handler, task)
            .catch(reason => {
              // Ignore errors, to allow the document to load.
            })
            .then(() => finishWorkerTask(task)),
          pdfManager.loadXfaImages(),
        ]);
      }

      const [numPages, fingerprints] = await Promise.all([
        pdfManager.ensureDoc("numPages"),
        pdfManager.ensureDoc("fingerprints"),
      ]);

      // Get htmlForXfa after numPages to avoid to create HTML twice.
      const htmlForXfa = isPureXfa
        ? await pdfManager.ensureDoc("htmlForXfa")
        : null;

      return { numPages, fingerprints, htmlForXfa };
    }

    function getPdfManager(data, evaluatorOptions, enableXfa) {
      const pdfManagerCapability = createPromiseCapability();
      let newPdfManager;

      const source = data.source;
      if (source.data) {
        try {
          newPdfManager = new LocalPdfManager(
            docId,
            source.data,
            source.password,
            evaluatorOptions,
            enableXfa,
            docBaseUrl
          );
          pdfManagerCapability.resolve(newPdfManager);
        } catch (ex) {
          pdfManagerCapability.reject(ex);
        }
        return pdfManagerCapability.promise;
      }

      let pdfStream,
        cachedChunks = [];
      try {
        pdfStream = new PDFWorkerStream(handler);
      } catch (ex) {
        pdfManagerCapability.reject(ex);
        return pdfManagerCapability.promise;
      }

      const fullRequest = pdfStream.getFullReader();
      fullRequest.headersReady
        .then(function () {
          if (!fullRequest.isRangeSupported) {
            return;
          }

          // We don't need auto-fetch when streaming is enabled.
          const disableAutoFetch =
            source.disableAutoFetch || fullRequest.isStreamingSupported;
          newPdfManager = new NetworkPdfManager(
            docId,
            pdfStream,
            {
              msgHandler: handler,
              password: source.password,
              length: fullRequest.contentLength,
              disableAutoFetch,
              rangeChunkSize: source.rangeChunkSize,
            },
            evaluatorOptions,
            enableXfa,
            docBaseUrl
          );
          // There may be a chance that `newPdfManager` is not initialized for
          // the first few runs of `readchunk` block of code. Be sure to send
          // all cached chunks, if any, to chunked_stream via pdf_manager.
          for (let i = 0; i < cachedChunks.length; i++) {
            newPdfManager.sendProgressiveData(cachedChunks[i]);
          }

          cachedChunks = [];
          pdfManagerCapability.resolve(newPdfManager);
          cancelXHRs = null;
        })
        .catch(function (reason) {
          pdfManagerCapability.reject(reason);
          cancelXHRs = null;
        });

      let loaded = 0;
      const flushChunks = function () {
        const pdfFile = arraysToBytes(cachedChunks);
        if (source.length && pdfFile.length !== source.length) {
          warn("reported HTTP length is different from actual");
        }
        // the data is array, instantiating directly from it
        try {
          newPdfManager = new LocalPdfManager(
            docId,
            pdfFile,
            source.password,
            evaluatorOptions,
            enableXfa,
            docBaseUrl
          );
          pdfManagerCapability.resolve(newPdfManager);
        } catch (ex) {
          pdfManagerCapability.reject(ex);
        }
        cachedChunks = [];
      };
      const readPromise = new Promise(function (resolve, reject) {
        const readChunk = function ({ value, done }) {
          try {
            ensureNotTerminated();
            if (done) {
              if (!newPdfManager) {
                flushChunks();
              }
              cancelXHRs = null;
              return;
            }

            loaded += arrayByteLength(value);
            if (!fullRequest.isStreamingSupported) {
              handler.send("DocProgress", {
                loaded,
                total: Math.max(loaded, fullRequest.contentLength || 0),
              });
            }

            if (newPdfManager) {
              newPdfManager.sendProgressiveData(value);
            } else {
              cachedChunks.push(value);
            }

            fullRequest.read().then(readChunk, reject);
          } catch (e) {
            reject(e);
          }
        };
        fullRequest.read().then(readChunk, reject);
      });
      readPromise.catch(function (e) {
        pdfManagerCapability.reject(e);
        cancelXHRs = null;
      });

      cancelXHRs = function (reason) {
        pdfStream.cancelAllRequests(reason);
      };

      return pdfManagerCapability.promise;
    }

    function setupDoc(data) {
      function onSuccess(doc) {
        ensureNotTerminated();
        handler.send("GetDoc", { pdfInfo: doc });
      }

      function onFailure(ex) {
        ensureNotTerminated();

        if (ex instanceof PasswordException) {
          const task = new WorkerTask(`PasswordException: response ${ex.code}`);
          startWorkerTask(task);

          handler
            .sendWithPromise("PasswordRequest", ex)
            .then(function ({ password }) {
              finishWorkerTask(task);
              pdfManager.updatePassword(password);
              pdfManagerReady();
            })
            .catch(function () {
              finishWorkerTask(task);
              handler.send("DocException", ex);
            });
        } else if (
          ex instanceof InvalidPDFException ||
          ex instanceof MissingPDFException ||
          ex instanceof UnexpectedResponseException ||
          ex instanceof UnknownErrorException
        ) {
          handler.send("DocException", ex);
        } else {
          handler.send(
            "DocException",
            new UnknownErrorException(ex.message, ex.toString())
          );
        }
      }

      function pdfManagerReady() {
        ensureNotTerminated();

        loadDocument(false).then(onSuccess, function (reason) {
          ensureNotTerminated();

          // Try again with recoveryMode == true
          if (!(reason instanceof XRefParseException)) {
            onFailure(reason);
            return;
          }
          pdfManager.requestLoadedStream();
          pdfManager.onLoadedStream().then(function () {
            ensureNotTerminated();

            loadDocument(true).then(onSuccess, onFailure);
          });
        });
      }

      ensureNotTerminated();

      const evaluatorOptions = {
        maxImageSize: data.maxImageSize,
        disableFontFace: data.disableFontFace,
        ignoreErrors: data.ignoreErrors,
        isEvalSupported: data.isEvalSupported,
        fontExtraProperties: data.fontExtraProperties,
        useSystemFonts: data.useSystemFonts,
        cMapUrl: data.cMapUrl,
        standardFontDataUrl: data.standardFontDataUrl,
      };

      getPdfManager(data, evaluatorOptions, data.enableXfa)
        .then(function (newPdfManager) {
          if (terminated) {
            // We were in a process of setting up the manager, but it got
            // terminated in the middle.
            newPdfManager.terminate(
              new AbortException("Worker was terminated.")
            );
            throw new Error("Worker was terminated");
          }
          pdfManager = newPdfManager;

          pdfManager.onLoadedStream().then(function (stream) {
            handler.send("DataLoaded", { length: stream.bytes.byteLength });
          });
        })
        .then(pdfManagerReady, onFailure);
    }

    handler.on("GetPage", function wphSetupGetPage(data) {
      return pdfManager.getPage(data.pageIndex).then(function (page) {
        return Promise.all([
          pdfManager.ensure(page, "rotate"),
          pdfManager.ensure(page, "ref"),
          pdfManager.ensure(page, "userUnit"),
          pdfManager.ensure(page, "view"),
        ]).then(function ([rotate, ref, userUnit, view]) {
          return {
            rotate,
            ref,
            userUnit,
            view,
          };
        });
      });
    });

    handler.on("GetPageIndex", function wphSetupGetPageIndex({ ref }) {
      const pageRef = Ref.get(ref.num, ref.gen);
      return pdfManager.ensureCatalog("getPageIndex", [pageRef]);
    });

    handler.on("GetDestinations", function wphSetupGetDestinations(data) {
      return pdfManager.ensureCatalog("destinations");
    });

    handler.on("GetDestination", function wphSetupGetDestination(data) {
      return pdfManager.ensureCatalog("getDestination", [data.id]);
    });

    handler.on("GetPageLabels", function wphSetupGetPageLabels(data) {
      return pdfManager.ensureCatalog("pageLabels");
    });

    handler.on("GetPageLayout", function wphSetupGetPageLayout(data) {
      return pdfManager.ensureCatalog("pageLayout");
    });

    handler.on("GetPageMode", function wphSetupGetPageMode(data) {
      return pdfManager.ensureCatalog("pageMode");
    });

    handler.on("GetViewerPreferences", function (data) {
      return pdfManager.ensureCatalog("viewerPreferences");
    });

    handler.on("GetOpenAction", function (data) {
      return pdfManager.ensureCatalog("openAction");
    });

    handler.on("GetAttachments", function wphSetupGetAttachments(data) {
      return pdfManager.ensureCatalog("attachments");
    });

    handler.on("GetJavaScript", function wphSetupGetJavaScript(data) {
      return pdfManager.ensureCatalog("javaScript");
    });

    handler.on("GetDocJSActions", function wphSetupGetDocJSActions(data) {
      return pdfManager.ensureCatalog("jsActions");
    });

    handler.on("GetPageJSActions", function ({ pageIndex }) {
      return pdfManager.getPage(pageIndex).then(function (page) {
        return pdfManager.ensure(page, "jsActions");
      });
    });

    handler.on("GetOutline", function wphSetupGetOutline(data) {
      return pdfManager.ensureCatalog("documentOutline");
    });

    handler.on("GetOptionalContentConfig", function (data) {
      return pdfManager.ensureCatalog("optionalContentConfig");
    });

    handler.on("GetPermissions", function (data) {
      return pdfManager.ensureCatalog("permissions");
    });

    handler.on("GetMetadata", function wphSetupGetMetadata(data) {
      return Promise.all([
        pdfManager.ensureDoc("documentInfo"),
        pdfManager.ensureCatalog("metadata"),
      ]);
    });

    handler.on("GetMarkInfo", function wphSetupGetMarkInfo(data) {
      return pdfManager.ensureCatalog("markInfo");
    });

    handler.on("GetData", function wphSetupGetData(data) {
      pdfManager.requestLoadedStream();
      return pdfManager.onLoadedStream().then(function (stream) {
        return stream.bytes;
      });
    });

    handler.on("GetStats", function wphSetupGetStats(data) {
      return pdfManager.ensureXRef("stats");
    });

    handler.on("GetAnnotations", function ({ pageIndex, intent }) {
      return pdfManager.getPage(pageIndex).then(function (page) {
        return page.getAnnotationsData(intent);
      });
    });

    handler.on("GetFieldObjects", function (data) {
      return pdfManager.ensureDoc("fieldObjects");
    });

    handler.on("HasJSActions", function (data) {
      return pdfManager.ensureDoc("hasJSActions");
    });

    handler.on("GetCalculationOrderIds", function (data) {
      return pdfManager.ensureDoc("calculationOrderIds");
    });

    handler.on(
      "SaveDocument",
      function ({ isPureXfa, numPages, annotationStorage, filename }) {
        pdfManager.requestLoadedStream();

        const promises = [
          pdfManager.onLoadedStream(),
          pdfManager.ensureCatalog("acroForm"),
          pdfManager.ensureCatalog("acroFormRef"),
          pdfManager.ensureDoc("xref"),
          pdfManager.ensureDoc("startXRef"),
        ];

        if (isPureXfa) {
          promises.push(pdfManager.serializeXfaData(annotationStorage));
        } else {
          for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
            promises.push(
              pdfManager.getPage(pageIndex).then(function (page) {
                const task = new WorkerTask(`Save: page ${pageIndex}`);
                return page
                  .save(handler, task, annotationStorage)
                  .finally(function () {
                    finishWorkerTask(task);
                  });
              })
            );
          }
        }

        return Promise.all(promises).then(function ([
          stream,
          acroForm,
          acroFormRef,
          xref,
          startXRef,
          ...refs
        ]) {
          let newRefs = [];
          let xfaData = null;
          if (isPureXfa) {
            xfaData = refs[0];
            if (!xfaData) {
              return stream.bytes;
            }
          } else {
            for (const ref of refs) {
              newRefs = ref
                .filter(x => x !== null)
                .reduce((a, b) => a.concat(b), newRefs);
            }

            if (newRefs.length === 0) {
              // No new refs so just return the initial bytes
              return stream.bytes;
            }
          }

          const xfa = (acroForm instanceof Dict && acroForm.get("XFA")) || null;
          let xfaDatasets = null;
          let hasDatasets = false;
          if (Array.isArray(xfa)) {
            for (let i = 0, ii = xfa.length; i < ii; i += 2) {
              if (xfa[i] === "datasets") {
                xfaDatasets = xfa[i + 1];
                acroFormRef = null;
                hasDatasets = true;
              }
            }
            if (xfaDatasets === null) {
              xfaDatasets = xref.getNewRef();
            }
          } else {
            acroFormRef = null;
            // TODO: Support XFA streams.
            warn("Unsupported XFA type.");
          }

          let newXrefInfo = Object.create(null);
          if (xref.trailer) {
            // Get string info from Info in order to compute fileId.
            const infoObj = Object.create(null);
            const xrefInfo = xref.trailer.get("Info") || null;
            if (xrefInfo instanceof Dict) {
              xrefInfo.forEach((key, value) => {
                if (isString(key) && isString(value)) {
                  infoObj[key] = stringToPDFString(value);
                }
              });
            }

            newXrefInfo = {
              rootRef: xref.trailer.getRaw("Root") || null,
              encryptRef: xref.trailer.getRaw("Encrypt") || null,
              newRef: xref.getNewRef(),
              infoRef: xref.trailer.getRaw("Info") || null,
              info: infoObj,
              fileIds: xref.trailer.get("ID") || null,
              startXRef,
              filename,
            };
          }
          xref.resetNewRef();

          return incrementalUpdate({
            originalData: stream.bytes,
            xrefInfo: newXrefInfo,
            newRefs,
            xref,
            datasetsRef: xfaDatasets,
            hasDatasets,
            acroFormRef,
            acroForm,
            xfaData,
          });
        });
      }
    );

    handler.on("GetOperatorList", function wphSetupRenderPage(data, sink) {
      const pageIndex = data.pageIndex;
      pdfManager.getPage(pageIndex).then(function (page) {
        const task = new WorkerTask(`GetOperatorList: page ${pageIndex}`);
        startWorkerTask(task);

        // NOTE: Keep this condition in sync with the `info` helper function.
        const start = verbosity >= VerbosityLevel.INFOS ? Date.now() : 0;

        // Pre compile the pdf page and fetch the fonts/images.
        page
          .getOperatorList({
            handler,
            sink,
            task,
            intent: data.intent,
            cacheKey: data.cacheKey,
            annotationStorage: data.annotationStorage,
          })
          .then(
            function (operatorListInfo) {
              finishWorkerTask(task);

              if (start) {
                info(
                  `page=${pageIndex + 1} - getOperatorList: time=` +
                    `${Date.now() - start}ms, len=${operatorListInfo.length}`
                );
              }
              sink.close();
            },
            function (reason) {
              finishWorkerTask(task);
              if (task.terminated) {
                return; // ignoring errors from the terminated thread
              }
              // For compatibility with older behavior, generating unknown
              // unsupported feature notification on errors.
              handler.send("UnsupportedFeature", {
                featureId: UNSUPPORTED_FEATURES.errorOperatorList,
              });

              sink.error(reason);

              // TODO: Should `reason` be re-thrown here (currently that casues
              //       "Uncaught exception: ..." messages in the console)?
            }
          );
      });
    });

    handler.on("GetTextContent", function wphExtractText(data, sink) {
      const pageIndex = data.pageIndex;
      sink.onPull = function (desiredSize) {};
      sink.onCancel = function (reason) {};

      pdfManager.getPage(pageIndex).then(function (page) {
        const task = new WorkerTask("GetTextContent: page " + pageIndex);
        startWorkerTask(task);

        // NOTE: Keep this condition in sync with the `info` helper function.
        const start = verbosity >= VerbosityLevel.INFOS ? Date.now() : 0;

        page
          .extractTextContent({
            handler,
            task,
            sink,
            normalizeWhitespace: data.normalizeWhitespace,
            includeMarkedContent: data.includeMarkedContent,
            combineTextItems: data.combineTextItems,
          })
          .then(
            function () {
              finishWorkerTask(task);

              if (start) {
                info(
                  `page=${pageIndex + 1} - getTextContent: time=` +
                    `${Date.now() - start}ms`
                );
              }
              sink.close();
            },
            function (reason) {
              finishWorkerTask(task);
              if (task.terminated) {
                return; // ignoring errors from the terminated thread
              }
              sink.error(reason);

              // TODO: Should `reason` be re-thrown here (currently that casues
              //       "Uncaught exception: ..." messages in the console)?
            }
          );
      });
    });

    handler.on("GetStructTree", function wphGetStructTree(data) {
      return pdfManager.getPage(data.pageIndex).then(function (page) {
        return pdfManager.ensure(page, "getStructTree");
      });
    });

    handler.on("FontFallback", function (data) {
      return pdfManager.fontFallback(data.id, handler);
    });

    handler.on("Cleanup", function wphCleanup(data) {
      return pdfManager.cleanup(/* manuallyTriggered = */ true);
    });

    handler.on("Terminate", function wphTerminate(data) {
      terminated = true;

      const waitOn = [];
      if (pdfManager) {
        pdfManager.terminate(new AbortException("Worker was terminated."));

        const cleanupPromise = pdfManager.cleanup();
        waitOn.push(cleanupPromise);

        pdfManager = null;
      } else {
        clearPrimitiveCaches();
      }
      if (cancelXHRs) {
        cancelXHRs(new AbortException("Worker was terminated."));
      }

      for (const task of WorkerTasks) {
        waitOn.push(task.finished);
        task.terminate();
      }

      return Promise.all(waitOn).then(function () {
        // Notice that even if we destroying handler, resolved response promise
        // must be sent back.
        handler.destroy();
        handler = null;
      });
    });

    handler.on("Ready", function wphReady(data) {
      setupDoc(docParams);
      docParams = null; // we don't need docParams anymore -- saving memory.
    });
    return workerHandlerName;
  }

  static initializeFromPort(port) {
    const handler = new MessageHandler("worker", "main", port);
    WorkerMessageHandler.setup(handler, port);
    handler.send("ready", null);
  }
}

function isMessagePort(maybePort) {
  return (
    typeof maybePort.postMessage === "function" && "onmessage" in maybePort
  );
}

// Worker thread (and not Node.js)?
if (
  typeof window === "undefined" &&
  !isNodeJS &&
  typeof self !== "undefined" &&
  isMessagePort(self)
) {
  WorkerMessageHandler.initializeFromPort(self);
}

export { WorkerMessageHandler, WorkerTask };


text:
/* @(#)s_fabs.c 5.1 93/09/24 */
/*
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
 * software is freely granted, provided that this notice
 * is preserved.
 * ====================================================
 */

#ifndef lint
static char rcsid[] = "$FreeBSD: soc2013/dpl/head/lib/msun/src/s_fabs.c 97456 2002-05-28 18:15:04Z alfred $";
#endif

/*
 * fabs(x) returns the absolute value of x.
 */

#include "math.h"
#include "math_private.h"

double
fabs(double x)
{
	u_int32_t high;
	GET_HIGH_WORD(high,x);
	SET_HIGH_WORD(x,high&0x7fffffff);
        return x;
}


text:
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"

#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"

namespace blink {

namespace {

bool IsInlineContainerForNode(const NGBlockNode& node,
                              const LayoutObject* inline_container) {
  return inline_container && inline_container->IsLayoutInline() &&
         inline_container->CanContainOutOfFlowPositionedElement(
             node.Style().GetPosition());
}

}  // namespace

void NGContainerFragmentBuilder::ReplaceChild(
    wtf_size_t index,
    const NGPhysicalFragment& new_child,
    const LogicalOffset offset) {
  DCHECK_LT(index, children_.size());
  children_[index] = ChildWithOffset(offset, std::move(&new_child));
}

// Propagate data in |child| to this fragment. The |child| will then be added as
// a child fragment or a child fragment item.
void NGContainerFragmentBuilder::PropagateChildData(
    const NGPhysicalFragment& child,
    LogicalOffset child_offset,
    LogicalOffset relative_offset,
    const NGInlineContainer<LogicalOffset>* inline_container,
    absl::optional<LayoutUnit> adjustment_for_oof_propagation) {
  if (adjustment_for_oof_propagation &&
      child.NeedsOOFPositionedInfoPropagation()) {
    PropagateOOFPositionedInfo(child, child_offset, relative_offset,
                               /* offset_adjustment */ LogicalOffset(),
                               inline_container,
                               *adjustment_for_oof_propagation);
  }

  // We only need to report if inflow or floating elements depend on the
  // percentage resolution block-size. OOF-positioned children resolve their
  // percentages against the "final" size of their parent.
  if (!has_descendant_that_depends_on_percentage_block_size_) {
    if (child.DependsOnPercentageBlockSize() && !child.IsOutOfFlowPositioned())
      has_descendant_that_depends_on_percentage_block_size_ = true;

    // We may have a child which has the following style:
    //

    // We need to mark this as depending on our %-block-size for the its offset
    // to be correctly calculated. This is *slightly* too broad as it only
    // depends on the available block-size, rather than the %-block-size.
    const auto& child_style = child.Style();
    if (child.IsCSSBox() && child_style.GetPosition() == EPosition::kRelative) {
      if (IsHorizontalWritingMode(Style().GetWritingMode())) {
        if (child_style.Top().IsPercentOrCalc() ||
            child_style.Bottom().IsPercentOrCalc())
          has_descendant_that_depends_on_percentage_block_size_ = true;
      } else {
        if (child_style.Left().IsPercentOrCalc() ||
            child_style.Right().IsPercentOrCalc())
          has_descendant_that_depends_on_percentage_block_size_ = true;
      }
    }
  }

  // Compute |has_floating_descendants_for_paint_| to optimize tree traversal
  // in paint.
  if (!has_floating_descendants_for_paint_) {
    if (child.IsFloating() || child.IsLegacyLayoutRoot() ||
        (child.HasFloatingDescendantsForPaint() &&
         !child.IsPaintedAtomically()))
      has_floating_descendants_for_paint_ = true;
  }

  // The |has_adjoining_object_descendants_| is used to determine if a fragment
  // can be re-used when preceding floats are present.
  // If a fragment doesn't have any adjoining object descendants, and is
  // self-collapsing, it can be "shifted" anywhere.
  if (!has_adjoining_object_descendants_) {
    if (!child.IsFormattingContextRoot() &&
        child.HasAdjoiningObjectDescendants())
      has_adjoining_object_descendants_ = true;
  }

  // Collect any (block) break tokens, but skip break tokens for fragmentainers,
  // as they should only escape a fragmentation context at the discretion of the
  // fragmentation context. Also skip this if there's a pre-set break token.
  if (has_block_fragmentation_ && !child.IsFragmentainerBox() &&
      !break_token_) {
    const NGBreakToken* child_break_token = child.BreakToken();
    switch (child.Type()) {
      case NGPhysicalFragment::kFragmentBox:
        if (child_break_token)
          child_break_tokens_.push_back(child_break_token);
        break;
      case NGPhysicalFragment::kFragmentLineBox:
        // We only care about the break token from the last line box added. This
        // is where we'll resume if we decide to block-fragment. Note that
        // child_break_token is nullptr if this is the last line to be generated
        // from the node.
        last_inline_break_token_ = To<NGInlineBreakToken>(child_break_token);
        line_count_++;
        break;
    }
  }
}

void NGContainerFragmentBuilder::AddChildInternal(
    scoped_refptr<const NGPhysicalFragment> child,
    const LogicalOffset& child_offset) {
  // In order to know where list-markers are within the children list (for the
  // |NGSimplifiedLayoutAlgorithm|) we always place them as the first child.
  if (child->IsListMarker()) {
    children_.push_front(ChildWithOffset(child_offset, std::move(child)));
    return;
  }

  if (child->IsTextControlPlaceholder()) {
    // ::placeholder should be followed by another block in order to paint
    // ::placeholder earlier.
    const wtf_size_t size = children_.size();
    if (size > 0) {
      children_.insert(size - 1,
                       ChildWithOffset(child_offset, std::move(child)));
      return;
    }
  }

  children_.emplace_back(child_offset, std::move(child));
}

void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
    NGBlockNode child,
    const LogicalOffset& child_offset,
    NGLogicalStaticPosition::InlineEdge inline_edge,
    NGLogicalStaticPosition::BlockEdge block_edge,
    bool needs_block_offset_adjustment) {
  DCHECK(child);

  // If an OOF-positioned candidate has a static-position which uses a
  // non-block-start edge, we may need to adjust its static-position when the
  // final block-size is known.
  needs_block_offset_adjustment &=
      block_edge != NGLogicalStaticPosition::BlockEdge::kBlockStart;
  has_oof_candidate_that_needs_block_offset_adjustment_ |=
      needs_block_offset_adjustment;

  oof_positioned_candidates_.emplace_back(
      child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge},
      NGInlineContainer<LogicalOffset>(), needs_block_offset_adjustment,
      /* containing_block */ NGContainingBlock<LogicalOffset>(),
      /* fixedpos_containing_block */ NGContainingBlock<LogicalOffset>());
}

void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
    const NGLogicalOutOfFlowPositionedNode& candidate) {
  oof_positioned_candidates_.emplace_back(candidate);
}

void NGContainerFragmentBuilder::AddOutOfFlowInlineChildCandidate(
    NGBlockNode child,
    const LogicalOffset& child_offset,
    TextDirection inline_container_direction) {
  DCHECK(node_.IsInline() || layout_object_->IsLayoutInline());

  // As all inline-level fragments are built in the line-logical coordinate
  // system (Direction() is kLtr), we need to know the direction of the
  // parent element to correctly determine an OOF childs static position.
  AddOutOfFlowChildCandidate(child, child_offset,
                             IsLtr(inline_container_direction)
                                 ? NGLogicalStaticPosition::kInlineStart
                                 : NGLogicalStaticPosition::kInlineEnd,
                             NGLogicalStaticPosition::kBlockStart);
}

void NGContainerFragmentBuilder::AddOutOfFlowFragmentainerDescendant(
    const NGLogicalOutOfFlowPositionedNode& descendant) {
  oof_positioned_fragmentainer_descendants_.push_back(descendant);
}

void NGContainerFragmentBuilder::AddOutOfFlowDescendant(
    const NGLogicalOutOfFlowPositionedNode& descendant) {
  oof_positioned_descendants_.push_back(descendant);
}

void NGContainerFragmentBuilder::SwapOutOfFlowPositionedCandidates(
    Vector<NGLogicalOutOfFlowPositionedNode>* candidates) {
  DCHECK(candidates->IsEmpty());
  std::swap(oof_positioned_candidates_, *candidates);

  if (!has_oof_candidate_that_needs_block_offset_adjustment_)
    return;

  using BlockEdge = NGLogicalStaticPosition::BlockEdge;

  // We might have an OOF-positioned candidate whose static-position depends on
  // the final block-size of this fragment.
  DCHECK_NE(BlockSize(), kIndefiniteSize);
  for (auto& candidate : *candidates) {
    if (!candidate.needs_block_offset_adjustment)
      continue;

    if (candidate.static_position.block_edge == BlockEdge::kBlockCenter)
      candidate.static_position.offset.block_offset += BlockSize() / 2;
    else if (candidate.static_position.block_edge == BlockEdge::kBlockEnd)
      candidate.static_position.offset.block_offset += BlockSize();
    candidate.needs_block_offset_adjustment = false;
  }

  has_oof_candidate_that_needs_block_offset_adjustment_ = false;
}

void NGContainerFragmentBuilder::AddMulticolWithPendingOOFs(
    const NGBlockNode& multicol,
    NGMulticolWithPendingOOFs<LogicalOffset> multicol_info) {
  DCHECK(To<LayoutBlockFlow>(multicol.GetLayoutBox())->MultiColumnFlowThread());
  auto it = multicols_with_pending_oofs_.find(multicol.GetLayoutBox());
  if (it != multicols_with_pending_oofs_.end())
    return;
  multicols_with_pending_oofs_.insert(multicol.GetLayoutBox(), multicol_info);
}

void NGContainerFragmentBuilder::SwapMulticolsWithPendingOOFs(
    MulticolCollection* multicols_with_pending_oofs) {
  DCHECK(multicols_with_pending_oofs->IsEmpty());
  std::swap(multicols_with_pending_oofs_, *multicols_with_pending_oofs);
}

void NGContainerFragmentBuilder::SwapOutOfFlowFragmentainerDescendants(
    Vector<NGLogicalOutOfFlowPositionedNode>* descendants) {
  DCHECK(descendants->IsEmpty());
  DCHECK(!has_oof_candidate_that_needs_block_offset_adjustment_);
  std::swap(oof_positioned_fragmentainer_descendants_, *descendants);
}

void NGContainerFragmentBuilder::TransferOutOfFlowCandidates(
    NGContainerFragmentBuilder* destination_builder,
    LogicalOffset additional_offset,
    const NGMulticolWithPendingOOFs<LogicalOffset>* multicol) {
  for (auto& candidate : oof_positioned_candidates_) {
    NGBlockNode node = candidate.Node();
    candidate.static_position.offset += additional_offset;
    if (multicol && multicol->fixedpos_containing_block.fragment &&
        node.Style().GetPosition() == EPosition::kFixed) {
      // A fixedpos containing block was found in |multicol|. Add the fixedpos
      // as a fragmentainer descendant instead.
      destination_builder->AddOutOfFlowFragmentainerDescendant(
          {node, candidate.static_position, candidate.inline_container,
           candidate.needs_block_offset_adjustment,
           multicol->fixedpos_containing_block,
           multicol->fixedpos_containing_block});
      continue;
    }
    destination_builder->AddOutOfFlowChildCandidate(candidate);
  }
  oof_positioned_candidates_.clear();
}

void NGContainerFragmentBuilder::
    MoveOutOfFlowDescendantCandidatesToDescendants() {
  DCHECK(oof_positioned_descendants_.IsEmpty());
  std::swap(oof_positioned_candidates_, oof_positioned_descendants_);

  if (!layout_object_->IsInline())
    return;

  for (auto& candidate : oof_positioned_descendants_) {
    // If we are inside the inline algorithm, (and creating a fragment for a
    //  or similar), we may add a child (e.g. an atomic-inline) which has
    // OOF descandants.
    //
    // This checks if the object creating this box will be the container for
    // the given descendant.
    if (!candidate.inline_container.container &&
        IsInlineContainerForNode(candidate.Node(), layout_object_)) {
      candidate.inline_container = NGInlineContainer<LogicalOffset>(
          To<LayoutInline>(layout_object_),
          /* relative_offset */ LogicalOffset());
    }

    // Ensure that the inline_container is a continuation root.
    if (candidate.inline_container.container) {
      candidate.inline_container.container = To<LayoutInline>(
          candidate.inline_container.container->ContinuationRoot());
    }
  }
}

void NGContainerFragmentBuilder::PropagateOOFPositionedInfo(
    const NGPhysicalFragment& fragment,
    LogicalOffset offset,
    LogicalOffset relative_offset,
    LogicalOffset offset_adjustment,
    const NGInlineContainer<LogicalOffset>* inline_container,
    LayoutUnit containing_block_adjustment,
    const NGContainingBlock<LogicalOffset>* fixedpos_containing_block,
    LogicalOffset additional_fixedpos_offset) {
  // Calling this method without any work to do is expensive, even if it ends up
  // skipping all its parts (probably due to its size). Make sure that we have a
  // reason to be here.
  DCHECK(fragment.NeedsOOFPositionedInfoPropagation());

  LogicalOffset adjusted_offset = offset + offset_adjustment + relative_offset;

  // Collect the child's out of flow descendants.
  const WritingModeConverter converter(GetWritingDirection(), fragment.Size());
  for (const auto& descendant : fragment.OutOfFlowPositionedDescendants()) {
    NGBlockNode node = descendant.Node();
    NGLogicalStaticPosition static_position =
        descendant.StaticPosition().ConvertToLogical(converter);

    NGInlineContainer<LogicalOffset> new_inline_container;
    if (descendant.inline_container.container) {
      new_inline_container.container = descendant.inline_container.container;
      new_inline_container.relative_offset =
          converter.ToLogical(descendant.inline_container.relative_offset,
                              PhysicalSize()) +
          relative_offset;
    } else if (inline_container &&
               IsInlineContainerForNode(node, inline_container->container)) {
      new_inline_container = *inline_container;
    }

    // If an OOF element is inside a fragmentation context, it will be laid out
    // once it reaches the fragmentation context root. However, if such OOF
    // elements have fixedpos descendants, those descendants will not find their
    // containing block if the containing block lives inside the fragmentation
    // context root. In this case, the containing block will be passed in via
    // |fixedpos_containing_block|. If one exists, add the fixedpos as a
    // fragmentainer descendant with the correct containing block and static
    // position. In the case of nested fragmentation, the fixedpos containing
    // block may be in an outer fragmentation context root. In such cases,
    // the fixedpos will be added as a fragmentainer descendant at a later time.
    // However, an |additional_fixedpos_offset| should be applied if one is
    // provided.
    if ((fixedpos_containing_block ||
         additional_fixedpos_offset != LogicalOffset()) &&
        node.Style().GetPosition() == EPosition::kFixed) {
      static_position.offset += additional_fixedpos_offset;
      // Relative offsets should be applied after fragmentation. However, if
      // there is any relative offset that occurrend before the fixedpos reached
      // its containing block, that relative offset should be applied to the
      // static position (before fragmentation).
      static_position.offset +=
          relative_offset - fixedpos_containing_block->relative_offset;
      if (fixedpos_containing_block && fixedpos_containing_block->fragment) {
        AddOutOfFlowFragmentainerDescendant(
            {node, static_position, new_inline_container,
             /* needs_block_offset_adjustment */ false,
             *fixedpos_containing_block, *fixedpos_containing_block});
        continue;
      }
    }
    static_position.offset += adjusted_offset;

    // |oof_positioned_candidates_| should not have duplicated entries.
    DCHECK(std::none_of(
        oof_positioned_candidates_.begin(), oof_positioned_candidates_.end(),
        [&node](const NGLogicalOutOfFlowPositionedNode& oof_node) {
          return oof_node.Node() == node;
        }));
    oof_positioned_candidates_.emplace_back(node, static_position,
                                            new_inline_container);
  }

  const NGFragmentedOutOfFlowData* oof_data =
      fragment.FragmentedOutOfFlowData();
  if (!oof_data)
    return;
  DCHECK(!oof_data->multicols_with_pending_oofs.IsEmpty() ||
         !oof_data->oof_positioned_fragmentainer_descendants.IsEmpty());
  const NGPhysicalBoxFragment* box_fragment =
      DynamicTo<NGPhysicalBoxFragment>(&fragment);

  if (!oof_data->multicols_with_pending_oofs.IsEmpty()) {
    const auto& multicols_with_pending_oofs =
        oof_data->multicols_with_pending_oofs;
    for (auto& multicol : multicols_with_pending_oofs) {
      auto& multicol_info = multicol.value;
      LogicalOffset multicol_offset =
          converter.ToLogical(multicol_info.multicol_offset, PhysicalSize());

      const NGPhysicalFragment* fixedpos_containing_block_fragment =
          multicol_info.fixedpos_containing_block.fragment.get();
      if (!fixedpos_containing_block_fragment && fragment.GetLayoutObject() &&
          fragment.GetLayoutObject()->CanContainFixedPositionObjects()) {
        DCHECK(box_fragment);  // shouldn't be line box by |GetLayoutObject()|.
        fixedpos_containing_block_fragment = box_fragment;
      }

      // If a fixedpos containing block was found, the |multicol_offset|
      // should remain relative to the fixedpos containing block. Otherwise,
      // continue to adjust the |multicol_offset| to be relative to the current
      // |fragment|.
      LogicalOffset fixedpos_containing_block_offset;
      LogicalOffset fixedpos_containing_block_rel_offset;
      if (fixedpos_containing_block_fragment) {
        fixedpos_containing_block_offset =
            converter.ToLogical(multicol_info.fixedpos_containing_block.offset,
                                fixedpos_containing_block_fragment->Size());
        fixedpos_containing_block_rel_offset = converter.ToLogical(
            multicol_info.fixedpos_containing_block.relative_offset,
            fixedpos_containing_block_fragment->Size());
        fixedpos_containing_block_rel_offset += relative_offset;
        // We want the fixedpos containing block offset to be the offset from
        // the containing block to the top of the fragmentation context root,
        // such that it includes the block offset contributions of previous
        // fragmentainers. The block contribution from previous fragmentainers
        // has already been applied. As such, avoid unnecessarily adding an
        // additional inline/block offset of any fragmentainers.
        if (!fragment.IsFragmentainerBox())
          fixedpos_containing_block_offset += offset;
        fixedpos_containing_block_offset.block_offset +=
            containing_block_adjustment;
      } else {
        multicol_offset += adjusted_offset;
      }
      AddMulticolWithPendingOOFs(
          NGBlockNode(multicol.key),
          NGMulticolWithPendingOOFs<LogicalOffset>(
              multicol_offset, NGContainingBlock<LogicalOffset>(
                                   fixedpos_containing_block_offset,
                                   fixedpos_containing_block_rel_offset,
                                   fixedpos_containing_block_fragment)));
    }
  }

  if (oof_data->oof_positioned_fragmentainer_descendants.IsEmpty())
    return;

  const auto& out_of_flow_fragmentainer_descendants =
      oof_data->oof_positioned_fragmentainer_descendants;
  for (const auto& descendant : out_of_flow_fragmentainer_descendants) {
    const NGPhysicalFragment* containing_block_fragment =
        descendant.containing_block.fragment.get();
    if (!containing_block_fragment) {
      DCHECK(box_fragment);
      containing_block_fragment = box_fragment;
    } else if (box_fragment && box_fragment->IsFragmentationContextRoot()) {
      // If we find a multicol with OOF positioned fragmentainer descendants,
      // then that multicol is an inner multicol with pending OOFs. Those OOFs
      // will be laid out inside the inner multicol when we reach the outermost
      // fragmentation context, so we should not propagate those OOFs up the
      // tree any further.
      continue;
    }

    LogicalOffset containing_block_offset = converter.ToLogical(
        descendant.containing_block.offset, containing_block_fragment->Size());
    LogicalOffset containing_block_rel_offset =
        converter.ToLogical(descendant.containing_block.relative_offset,
                            containing_block_fragment->Size());
    containing_block_rel_offset += relative_offset;
    if (!fragment.IsFragmentainerBox())
      containing_block_offset += offset;
    containing_block_offset.block_offset += containing_block_adjustment;

    const NGPhysicalFragment* fixedpos_containing_block_fragment =
        descendant.fixedpos_containing_block.fragment.get();
    if (!fixedpos_containing_block_fragment && fragment.GetLayoutObject() &&
        fragment.GetLayoutObject()->CanContainFixedPositionObjects()) {
      DCHECK(box_fragment);  // shouldn't ba line box by |GetLayoutObject()|.
      fixedpos_containing_block_fragment = box_fragment;
    }

    LogicalOffset fixedpos_containing_block_offset;
    LogicalOffset fixedpos_containing_block_rel_offset;
    if (fixedpos_containing_block_fragment) {
      fixedpos_containing_block_offset =
          converter.ToLogical(descendant.fixedpos_containing_block.offset,
                              fixedpos_containing_block_fragment->Size());
      fixedpos_containing_block_rel_offset = converter.ToLogical(
          descendant.fixedpos_containing_block.relative_offset,
          fixedpos_containing_block_fragment->Size());
      fixedpos_containing_block_rel_offset += relative_offset;
      if (!fragment.IsFragmentainerBox())
        fixedpos_containing_block_offset += offset;
      fixedpos_containing_block_offset.block_offset +=
          containing_block_adjustment;
    }

    if (!fixedpos_containing_block_fragment && fixedpos_containing_block) {
      fixedpos_containing_block_fragment =
          fixedpos_containing_block->fragment.get();
      fixedpos_containing_block_offset = fixedpos_containing_block->offset;
      fixedpos_containing_block_rel_offset =
          fixedpos_containing_block->relative_offset;
    }

    LogicalOffset inline_relative_offset = converter.ToLogical(
        descendant.inline_container.relative_offset, PhysicalSize());
    NGInlineContainer<LogicalOffset> new_inline_container(
        descendant.inline_container.container, inline_relative_offset);

    // The static position should remain relative to its containing block
    // fragment.
    const WritingModeConverter containing_block_converter(
        GetWritingDirection(), containing_block_fragment->Size());
    NGLogicalStaticPosition static_position =
        descendant.StaticPosition().ConvertToLogical(
            containing_block_converter);

    // The relative offset should be applied after fragmentation. Subtract out
    // the accumulated relative offset from the inline container to the
    // containing block so that it can be re-applied at the correct time.
    if (new_inline_container.container && box_fragment &&
        containing_block_fragment == box_fragment)
      static_position.offset -= inline_relative_offset;

    AddOutOfFlowFragmentainerDescendant(
        {descendant.Node(), static_position, new_inline_container,
         /* needs_block_offset_adjustment */ false,
         NGContainingBlock<LogicalOffset>(containing_block_offset,
                                          containing_block_rel_offset,
                                          containing_block_fragment),
         NGContainingBlock<LogicalOffset>(fixedpos_containing_block_offset,
                                          fixedpos_containing_block_rel_offset,
                                          fixedpos_containing_block_fragment)});
  }
}

scoped_refptr<const NGLayoutResult> NGContainerFragmentBuilder::Abort(
    NGLayoutResult::EStatus status) {
  return base::AdoptRef(new NGLayoutResult(
      NGLayoutResult::NGContainerFragmentBuilderPassKey(), status, this));
}

#if DCHECK_IS_ON()

String NGContainerFragmentBuilder::ToString() const {
  StringBuilder builder;
  builder.AppendFormat("ContainerFragment %.2fx%.2f, Children %u\n",
                       InlineSize().ToFloat(), BlockSize().ToFloat(),
                       children_.size());
  for (auto& child : children_) {
    builder.Append(child.fragment->DumpFragmentTree(
        NGPhysicalFragment::DumpAll & ~NGPhysicalFragment::DumpHeaderText));
  }
  return builder.ToString();
}

#endif

}  // namespace blink