For example, suppose an end-entity certificate E were signed by intermediate I that was signed by root R. Further suppose that R were cross-signed by another root T, producing intermediate certificate R'. Two valid paths are E -> I -> R and E -> I -> R' -> T. At the step where mozilla::pkix is trying to find an issuer for I, the trust domain finds both R and R' as potential issuers. However, only R is a trust anchor - R' is not. So, the trust domain has mozilla::pkix try that one first. It successfully verifies, so the library returns the result E -> I -> R. If at some later point R were distrusted, that chain would not verify successfully. mozilla::pkix would then ask the trust domain for another potential issuer of I, and the trust domain would provide R'. R' is not a trust anchor either, so mozilla::pkix asks for potential issuers of that certificate. The trust domain provides T, and mozilla::pkix verifies the chain, resulting in E -> I -> R' -> T.
Extended Validation changes the situation somewhat in that when mozilla::pkix is verifying an EV certificate, it must do so for a particular policy OID, and only certain roots are trusted for particular policy OIDs. This policy OID will be the first policy OID that is recognized by Firefox as a supported EV policy OID from the end-entity's certificatePolicies extension. Other than that, path building proceeds as before. So, using the example from before, suppose R were a trust anchor but not for a particular EV OID. Further suppose that T is also a trust anchor but is trusted for a particular EV OID. When evaluating the potential chain E -> I -> R, the trust domain determines that R is not a trust anchor for the policy being verified for, so mozilla::pkix keeps searching. It finds potential chain E -> I -> R' -> T, where T is trusted for that EV OID, and thus it verifies and returns that chain.
Unlike the other NSS libraries, mozilla::pkix is written in C++ and can take advantage of more modern language features.